From 521dc1fb2c7f359aa3c2f7013ce878606a5a8a84 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 6 May 2017 16:21:42 -0400 Subject: [PATCH 01/37] 3.2.14.1 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 0cf34eeacc..caf7c1e63a 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.13.14")] +[assembly: AssemblyVersion("3.2.14.1")] From efc678863684c9ef4f739aed0ced087ba1d6b4c6 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 7 May 2017 14:15:00 -0400 Subject: [PATCH 02/37] 3.2.14.2 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index caf7c1e63a..66e6eb3653 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.14.1")] +[assembly: AssemblyVersion("3.2.14.2")] From 1dab9a60f4a2115f15df14b235c5ca64203be811 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 7 May 2017 16:02:32 -0400 Subject: [PATCH 03/37] rename methods --- .../Activity/ActivityRepository.cs | 4 +- .../SqliteDisplayPreferencesRepository.cs | 10 ++-- .../Data/SqliteExtensions.cs | 12 ++-- .../Data/SqliteFileOrganizationRepository.cs | 8 +-- .../Data/SqliteItemRepository.cs | 56 +++++++++---------- .../Data/SqliteUserDataRepository.cs | 8 +-- .../Data/SqliteUserRepository.cs | 6 +- .../SqliteNotificationsRepository.cs | 18 +++--- .../Security/AuthenticationRepository.cs | 6 +- .../Social/SharingRepository.cs | 6 +- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 +- 12 files changed, 70 insertions(+), 70 deletions(-) diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs index bf88358465..e9b6f7a404 100644 --- a/Emby.Server.Implementations/Activity/ActivityRepository.cs +++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs @@ -60,7 +60,7 @@ namespace Emby.Server.Implementations.Activity { using (var statement = db.PrepareStatement("replace into ActivityLogEntries (Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity) values (@Id, @Name, @Overview, @ShortOverview, @Type, @ItemId, @UserId, @DateCreated, @LogSeverity)")) { - statement.TryBind("@Id", entry.Id.ToGuidParamValue()); + statement.TryBind("@Id", entry.Id.ToGuidBlob()); statement.TryBind("@Name", entry.Name); statement.TryBind("@Overview", entry.Overview); @@ -168,7 +168,7 @@ namespace Emby.Server.Implementations.Activity var info = new ActivityLogEntry { - Id = reader[index].ReadGuid().ToString("N") + Id = reader[index].ReadGuidFromBlob().ToString("N") }; index++; diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs index f3d84315e9..4118bd1b21 100644 --- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs @@ -106,8 +106,8 @@ namespace Emby.Server.Implementations.Data using (var statement = connection.PrepareStatement("replace into userdisplaypreferences (id, userid, client, data) values (@id, @userId, @client, @data)")) { - statement.TryBind("@id", displayPreferences.Id.ToGuidParamValue()); - statement.TryBind("@userId", userId.ToGuidParamValue()); + statement.TryBind("@id", displayPreferences.Id.ToGuidBlob()); + statement.TryBind("@userId", userId.ToGuidBlob()); statement.TryBind("@client", client); statement.TryBind("@data", serialized); @@ -170,8 +170,8 @@ namespace Emby.Server.Implementations.Data { using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client")) { - statement.TryBind("@id", guidId.ToGuidParamValue()); - statement.TryBind("@userId", userId.ToGuidParamValue()); + statement.TryBind("@id", guidId.ToGuidBlob()); + statement.TryBind("@userId", userId.ToGuidBlob()); statement.TryBind("@client", client); foreach (var row in statement.ExecuteQuery()) @@ -204,7 +204,7 @@ namespace Emby.Server.Implementations.Data { using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId")) { - statement.TryBind("@userId", userId.ToGuidParamValue()); + statement.TryBind("@userId", userId.ToGuidBlob()); foreach (var row in statement.ExecuteQuery()) { diff --git a/Emby.Server.Implementations/Data/SqliteExtensions.cs b/Emby.Server.Implementations/Data/SqliteExtensions.cs index 783258a138..d2c851b3c6 100644 --- a/Emby.Server.Implementations/Data/SqliteExtensions.cs +++ b/Emby.Server.Implementations/Data/SqliteExtensions.cs @@ -26,17 +26,17 @@ namespace Emby.Server.Implementations.Data }); } - public static byte[] ToGuidParamValue(this string str) + public static byte[] ToGuidBlob(this string str) { - return ToGuidParamValue(new Guid(str)); + return ToGuidBlob(new Guid(str)); } - public static byte[] ToGuidParamValue(this Guid guid) + public static byte[] ToGuidBlob(this Guid guid) { return guid.ToByteArray(); } - public static Guid ReadGuid(this IResultSetValue result) + public static Guid ReadGuidFromBlob(this IResultSetValue result) { return new Guid(result.ToBlob()); } @@ -172,7 +172,7 @@ namespace Emby.Server.Implementations.Data public static Guid GetGuid(this IReadOnlyList result, int index) { - return result[index].ReadGuid(); + return result[index].ReadGuidFromBlob(); } private static void CheckName(string name) @@ -262,7 +262,7 @@ namespace Emby.Server.Implementations.Data IBindParameter bindParam; if (statement.BindParameters.TryGetValue(name, out bindParam)) { - bindParam.Bind(value.ToGuidParamValue()); + bindParam.Bind(value.ToGuidBlob()); } else { diff --git a/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs b/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs index 9fbe8669d1..a254962c94 100644 --- a/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs @@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.Data using (var statement = db.PrepareStatement(commandText)) { - statement.TryBind("@ResultId", result.Id.ToGuidParamValue()); + statement.TryBind("@ResultId", result.Id.ToGuidBlob()); statement.TryBind("@OriginalPath", result.OriginalPath); statement.TryBind("@TargetPath", result.TargetPath); @@ -100,7 +100,7 @@ namespace Emby.Server.Implementations.Data { using (var statement = db.PrepareStatement("delete from FileOrganizerResults where ResultId = @ResultId")) { - statement.TryBind("@ResultId", id.ToGuidParamValue()); + statement.TryBind("@ResultId", id.ToGuidBlob()); statement.MoveNext(); } }, TransactionMode); @@ -188,7 +188,7 @@ namespace Emby.Server.Implementations.Data { using (var statement = connection.PrepareStatement("select ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults where ResultId=@ResultId")) { - statement.TryBind("@ResultId", id.ToGuidParamValue()); + statement.TryBind("@ResultId", id.ToGuidBlob()); foreach (var row in statement.ExecuteQuery()) { @@ -207,7 +207,7 @@ namespace Emby.Server.Implementations.Data var result = new FileOrganizationResult { - Id = reader[0].ReadGuid().ToString("N") + Id = reader[0].ReadGuidFromBlob().ToString("N") }; index++; diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 61dce9bba3..28be49dc2f 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -2128,7 +2128,7 @@ namespace Emby.Server.Implementations.Data connection.RunInTransaction(db => { // First delete chapters - db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", id.ToGuidParamValue()); + db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", id.ToGuidBlob()); using (var saveChapterStatement = PrepareStatement(db, "replace into " + ChaptersTableName + " (ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath, ImageDateModified) values (@ItemId, @ChapterIndex, @StartPositionTicks, @Name, @ImagePath, @ImageDateModified)")) { @@ -2139,7 +2139,7 @@ namespace Emby.Server.Implementations.Data saveChapterStatement.Reset(); } - saveChapterStatement.TryBind("@ItemId", id.ToGuidParamValue()); + saveChapterStatement.TryBind("@ItemId", id.ToGuidBlob()); saveChapterStatement.TryBind("@ChapterIndex", index); saveChapterStatement.TryBind("@StartPositionTicks", chapter.StartPositionTicks); saveChapterStatement.TryBind("@Name", chapter.Name); @@ -2919,7 +2919,7 @@ namespace Emby.Server.Implementations.Data foreach (var row in statement.ExecuteQuery()) { - list.Add(row[0].ReadGuid()); + list.Add(row[0].ReadGuidFromBlob()); } } @@ -3113,7 +3113,7 @@ namespace Emby.Server.Implementations.Data foreach (var row in statement.ExecuteQuery()) { - list.Add(row[0].ReadGuid()); + list.Add(row[0].ReadGuidFromBlob()); } } } @@ -3643,7 +3643,7 @@ namespace Emby.Server.Implementations.Data clauses.Add("(select Name from TypedBaseItems where guid=" + paramName + ") in (select Name from People where ItemId=Guid)"); if (statement != null) { - statement.TryBind(paramName, personId.ToGuidParamValue()); + statement.TryBind(paramName, personId.ToGuidBlob()); } index++; } @@ -3843,7 +3843,7 @@ namespace Emby.Server.Implementations.Data clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type<=1)"); if (statement != null) { - statement.TryBind(paramName, artistId.ToGuidParamValue()); + statement.TryBind(paramName, artistId.ToGuidBlob()); } index++; } @@ -3862,7 +3862,7 @@ namespace Emby.Server.Implementations.Data clauses.Add("Album in (select Name from typedbaseitems where guid=" + paramName + ")"); if (statement != null) { - statement.TryBind(paramName, albumId.ToGuidParamValue()); + statement.TryBind(paramName, albumId.ToGuidBlob()); } index++; } @@ -3881,7 +3881,7 @@ namespace Emby.Server.Implementations.Data clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") not in (select CleanValue from itemvalues where ItemId=Guid and Type<=1)"); if (statement != null) { - statement.TryBind(paramName, artistId.ToGuidParamValue()); + statement.TryBind(paramName, artistId.ToGuidBlob()); } index++; } @@ -3900,7 +3900,7 @@ namespace Emby.Server.Implementations.Data clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=2)"); if (statement != null) { - statement.TryBind(paramName, genreId.ToGuidParamValue()); + statement.TryBind(paramName, genreId.ToGuidBlob()); } index++; } @@ -3953,7 +3953,7 @@ namespace Emby.Server.Implementations.Data clauses.Add("(select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=3)"); if (statement != null) { - statement.TryBind(paramName, studioId.ToGuidParamValue()); + statement.TryBind(paramName, studioId.ToGuidBlob()); } index++; } @@ -4521,22 +4521,22 @@ namespace Emby.Server.Implementations.Data connection.RunInTransaction(db => { // Delete people - ExecuteWithSingleParam(db, "delete from People where ItemId=@Id", id.ToGuidParamValue()); + ExecuteWithSingleParam(db, "delete from People where ItemId=@Id", id.ToGuidBlob()); // Delete chapters - ExecuteWithSingleParam(db, "delete from " + ChaptersTableName + " where ItemId=@Id", id.ToGuidParamValue()); + ExecuteWithSingleParam(db, "delete from " + ChaptersTableName + " where ItemId=@Id", id.ToGuidBlob()); // Delete media streams - ExecuteWithSingleParam(db, "delete from mediastreams where ItemId=@Id", id.ToGuidParamValue()); + ExecuteWithSingleParam(db, "delete from mediastreams where ItemId=@Id", id.ToGuidBlob()); // Delete ancestors - ExecuteWithSingleParam(db, "delete from AncestorIds where ItemId=@Id", id.ToGuidParamValue()); + ExecuteWithSingleParam(db, "delete from AncestorIds where ItemId=@Id", id.ToGuidBlob()); // Delete item values - ExecuteWithSingleParam(db, "delete from ItemValues where ItemId=@Id", id.ToGuidParamValue()); + ExecuteWithSingleParam(db, "delete from ItemValues where ItemId=@Id", id.ToGuidBlob()); // Delete the item - ExecuteWithSingleParam(db, "delete from TypedBaseItems where guid=@Id", id.ToGuidParamValue()); + ExecuteWithSingleParam(db, "delete from TypedBaseItems where guid=@Id", id.ToGuidBlob()); }, TransactionMode); } } @@ -4643,7 +4643,7 @@ namespace Emby.Server.Implementations.Data whereClauses.Add("ItemId=@ItemId"); if (statement != null) { - statement.TryBind("@ItemId", query.ItemId.ToGuidParamValue()); + statement.TryBind("@ItemId", query.ItemId.ToGuidBlob()); } } if (query.AppearsInItemId != Guid.Empty) @@ -4651,7 +4651,7 @@ namespace Emby.Server.Implementations.Data whereClauses.Add("Name in (Select Name from People where ItemId=@AppearsInItemId)"); if (statement != null) { - statement.TryBind("@AppearsInItemId", query.AppearsInItemId.ToGuidParamValue()); + statement.TryBind("@AppearsInItemId", query.AppearsInItemId.ToGuidBlob()); } } var queryPersonTypes = query.PersonTypes.Where(IsValidPersonType).ToList(); @@ -4730,14 +4730,14 @@ namespace Emby.Server.Implementations.Data // First delete deleteAncestorsStatement.Reset(); - deleteAncestorsStatement.TryBind("@ItemId", itemId.ToGuidParamValue()); + deleteAncestorsStatement.TryBind("@ItemId", itemId.ToGuidBlob()); deleteAncestorsStatement.MoveNext(); foreach (var ancestorId in ancestorIds) { updateAncestorsStatement.Reset(); - updateAncestorsStatement.TryBind("@ItemId", itemId.ToGuidParamValue()); - updateAncestorsStatement.TryBind("@AncestorId", ancestorId.ToGuidParamValue()); + updateAncestorsStatement.TryBind("@ItemId", itemId.ToGuidBlob()); + updateAncestorsStatement.TryBind("@AncestorId", ancestorId.ToGuidBlob()); updateAncestorsStatement.TryBind("@AncestorIdText", ancestorId.ToString("N")); updateAncestorsStatement.MoveNext(); } @@ -5198,7 +5198,7 @@ namespace Emby.Server.Implementations.Data CheckDisposed(); // First delete - db.Execute("delete from ItemValues where ItemId=@Id", itemId.ToGuidParamValue()); + db.Execute("delete from ItemValues where ItemId=@Id", itemId.ToGuidBlob()); using (var statement = PrepareStatement(db, "insert into ItemValues (ItemId, Type, Value, CleanValue) values (@ItemId, @Type, @Value, @CleanValue)")) { @@ -5214,7 +5214,7 @@ namespace Emby.Server.Implementations.Data statement.Reset(); - statement.TryBind("@ItemId", itemId.ToGuidParamValue()); + statement.TryBind("@ItemId", itemId.ToGuidBlob()); statement.TryBind("@Type", pair.Item1); statement.TryBind("@Value", itemValue); @@ -5252,7 +5252,7 @@ namespace Emby.Server.Implementations.Data { // First delete // "delete from People where ItemId=?" - connection.Execute("delete from People where ItemId=?", itemId.ToGuidParamValue()); + connection.Execute("delete from People where ItemId=?", itemId.ToGuidBlob()); var listIndex = 0; @@ -5266,7 +5266,7 @@ namespace Emby.Server.Implementations.Data statement.Reset(); } - statement.TryBind("@ItemId", itemId.ToGuidParamValue()); + statement.TryBind("@ItemId", itemId.ToGuidBlob()); statement.TryBind("@Name", person.Name); statement.TryBind("@Role", person.Role); statement.TryBind("@PersonType", person.Type); @@ -5339,7 +5339,7 @@ namespace Emby.Server.Implementations.Data using (var statement = PrepareStatementSafe(connection, cmdText)) { - statement.TryBind("@ItemId", query.ItemId.ToGuidParamValue()); + statement.TryBind("@ItemId", query.ItemId.ToGuidBlob()); if (query.Type.HasValue) { @@ -5383,7 +5383,7 @@ namespace Emby.Server.Implementations.Data using (var connection = CreateConnection()) { // First delete chapters - connection.Execute("delete from mediastreams where ItemId=@ItemId", id.ToGuidParamValue()); + connection.Execute("delete from mediastreams where ItemId=@ItemId", id.ToGuidBlob()); using (var statement = PrepareStatement(connection, string.Format("replace into mediastreams ({0}) values ({1})", string.Join(",", _mediaStreamSaveColumns), @@ -5393,7 +5393,7 @@ namespace Emby.Server.Implementations.Data { var paramList = new List(); - paramList.Add(id.ToGuidParamValue()); + paramList.Add(id.ToGuidBlob()); paramList.Add(stream.Index); paramList.Add(stream.Type.ToString()); paramList.Add(stream.Codec); diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index a31f0ed530..bf6388f5d8 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -213,7 +213,7 @@ namespace Emby.Server.Implementations.Data { using (var statement = db.PrepareStatement("replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)")) { - statement.TryBind("@userId", userId.ToGuidParamValue()); + statement.TryBind("@userId", userId.ToGuidBlob()); statement.TryBind("@key", key); if (userData.Rating.HasValue) @@ -311,7 +311,7 @@ namespace Emby.Server.Implementations.Data { using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key =@Key and userId=@UserId")) { - statement.TryBind("@UserId", userId.ToGuidParamValue()); + statement.TryBind("@UserId", userId.ToGuidBlob()); statement.TryBind("@Key", key); foreach (var row in statement.ExecuteQuery()) @@ -364,7 +364,7 @@ namespace Emby.Server.Implementations.Data { using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@UserId")) { - statement.TryBind("@UserId", userId.ToGuidParamValue()); + statement.TryBind("@UserId", userId.ToGuidBlob()); foreach (var row in statement.ExecuteQuery()) { @@ -386,7 +386,7 @@ namespace Emby.Server.Implementations.Data var userData = new UserItemData(); userData.Key = reader[0].ToString(); - userData.UserId = reader[1].ReadGuid(); + userData.UserId = reader[1].ReadGuidFromBlob(); if (reader[2].SQLiteType != SQLiteType.Null) { diff --git a/Emby.Server.Implementations/Data/SqliteUserRepository.cs b/Emby.Server.Implementations/Data/SqliteUserRepository.cs index b2b917e5eb..29959bcabe 100644 --- a/Emby.Server.Implementations/Data/SqliteUserRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserRepository.cs @@ -93,7 +93,7 @@ namespace Emby.Server.Implementations.Data { using (var statement = db.PrepareStatement("replace into users (guid, data) values (@guid, @data)")) { - statement.TryBind("@guid", user.Id.ToGuidParamValue()); + statement.TryBind("@guid", user.Id.ToGuidBlob()); statement.TryBind("@data", serialized); statement.MoveNext(); } @@ -116,7 +116,7 @@ namespace Emby.Server.Implementations.Data { foreach (var row in connection.Query("select guid,data from users")) { - var id = row[0].ReadGuid(); + var id = row[0].ReadGuidFromBlob(); using (var stream = _memoryStreamProvider.CreateNew(row[1].ToBlob())) { @@ -156,7 +156,7 @@ namespace Emby.Server.Implementations.Data { using (var statement = db.PrepareStatement("delete from users where guid=@id")) { - statement.TryBind("@id", user.Id.ToGuidParamValue()); + statement.TryBind("@id", user.Id.ToGuidBlob()); statement.MoveNext(); } }, TransactionMode); diff --git a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs index 76c7a7d77c..40752db800 100644 --- a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs +++ b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs @@ -81,7 +81,7 @@ namespace Emby.Server.Implementations.Notifications } clauses.Add("UserId=?"); - paramList.Add(query.UserId.ToGuidParamValue()); + paramList.Add(query.UserId.ToGuidBlob()); var whereClause = " where " + string.Join(" And ", clauses.ToArray()); @@ -133,7 +133,7 @@ namespace Emby.Server.Implementations.Notifications using (var statement = connection.PrepareStatement("select Level from Notifications where UserId=@UserId and IsRead=@IsRead")) { statement.TryBind("@IsRead", false); - statement.TryBind("@UserId", userId.ToGuidParamValue()); + statement.TryBind("@UserId", userId.ToGuidBlob()); var levels = new List(); @@ -159,8 +159,8 @@ namespace Emby.Server.Implementations.Notifications { var notification = new Notification { - Id = reader[0].ReadGuid().ToString("N"), - UserId = reader[1].ReadGuid().ToString("N"), + Id = reader[0].ReadGuidFromBlob().ToString("N"), + UserId = reader[1].ReadGuidFromBlob().ToString("N"), Date = reader[2].ReadDateTime(), Name = reader[3].ToString() }; @@ -251,8 +251,8 @@ namespace Emby.Server.Implementations.Notifications { using (var statement = conn.PrepareStatement("replace into Notifications (Id, UserId, Date, Name, Description, Url, Level, IsRead, Category, RelatedId) values (@Id, @UserId, @Date, @Name, @Description, @Url, @Level, @IsRead, @Category, @RelatedId)")) { - statement.TryBind("@Id", notification.Id.ToGuidParamValue()); - statement.TryBind("@UserId", notification.UserId.ToGuidParamValue()); + statement.TryBind("@Id", notification.Id.ToGuidBlob()); + statement.TryBind("@UserId", notification.UserId.ToGuidBlob()); statement.TryBind("@Date", notification.Date.ToDateTimeParamValue()); statement.TryBind("@Name", notification.Name); statement.TryBind("@Description", notification.Description); @@ -315,7 +315,7 @@ namespace Emby.Server.Implementations.Notifications using (var statement = conn.PrepareStatement("update Notifications set IsRead=@IsRead where UserId=@UserId")) { statement.TryBind("@IsRead", isRead); - statement.TryBind("@UserId", userId.ToGuidParamValue()); + statement.TryBind("@UserId", userId.ToGuidBlob()); statement.MoveNext(); } @@ -337,13 +337,13 @@ namespace Emby.Server.Implementations.Notifications using (var statement = conn.PrepareStatement("update Notifications set IsRead=@IsRead where UserId=@UserId and Id=@Id")) { statement.TryBind("@IsRead", isRead); - statement.TryBind("@UserId", userId.ToGuidParamValue()); + statement.TryBind("@UserId", userId.ToGuidBlob()); foreach (var id in notificationIdList) { statement.Reset(); - statement.TryBind("@Id", id.ToGuidParamValue()); + statement.TryBind("@Id", id.ToGuidBlob()); statement.MoveNext(); } diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index a2d61873b8..9ec0af6bb5 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -74,7 +74,7 @@ namespace Emby.Server.Implementations.Security { using (var statement = db.PrepareStatement("replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)")) { - statement.TryBind("@Id", info.Id.ToGuidParamValue()); + statement.TryBind("@Id", info.Id.ToGuidBlob()); statement.TryBind("@AccessToken", info.AccessToken); statement.TryBind("@DeviceId", info.DeviceId); @@ -259,7 +259,7 @@ namespace Emby.Server.Implementations.Security using (var statement = connection.PrepareStatement(commandText)) { - statement.BindParameters["@Id"].Bind(id.ToGuidParamValue()); + statement.BindParameters["@Id"].Bind(id.ToGuidBlob()); foreach (var row in statement.ExecuteQuery()) { @@ -275,7 +275,7 @@ namespace Emby.Server.Implementations.Security { var info = new AuthenticationInfo { - Id = reader[0].ReadGuid().ToString("N"), + Id = reader[0].ReadGuidFromBlob().ToString("N"), AccessToken = reader[1].ToString() }; diff --git a/Emby.Server.Implementations/Social/SharingRepository.cs b/Emby.Server.Implementations/Social/SharingRepository.cs index e8230947ec..46e9205bb2 100644 --- a/Emby.Server.Implementations/Social/SharingRepository.cs +++ b/Emby.Server.Implementations/Social/SharingRepository.cs @@ -61,7 +61,7 @@ namespace Emby.Server.Implementations.Social var commandText = "replace into Shares (Id, ItemId, UserId, ExpirationDate) values (?, ?, ?, ?)"; db.Execute(commandText, - info.Id.ToGuidParamValue(), + info.Id.ToGuidBlob(), info.ItemId, info.UserId, info.ExpirationDate.ToDateTimeParamValue()); @@ -84,7 +84,7 @@ namespace Emby.Server.Implementations.Social var commandText = "select Id, ItemId, UserId, ExpirationDate from Shares where id = ?"; var paramList = new List(); - paramList.Add(id.ToGuidParamValue()); + paramList.Add(id.ToGuidBlob()); foreach (var row in connection.Query(commandText, paramList.ToArray())) { @@ -100,7 +100,7 @@ namespace Emby.Server.Implementations.Social { var info = new SocialShareInfo(); - info.Id = reader[0].ReadGuid().ToString("N"); + info.Id = reader[0].ReadGuidFromBlob().ToString("N"); info.ItemId = reader[1].ToString(); info.UserId = reader[2].ToString(); info.ExpirationDate = reader[3].ReadDateTime(); diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index c86e9a71cd..64e4d14181 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.699 + 3.0.700 Emby.Common Emby Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index f68cf4e410..917288cb1e 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.699 + 3.0.700 Emby.Server.Core Emby Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Emby Server. Copyright © Emby 2013 - + From d57a50af3b3af5e389c1aff1bea34a1f2ada299e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 8 May 2017 14:05:47 -0400 Subject: [PATCH 04/37] add library monitor error handling --- Emby.Server.Core/IO/LibraryMonitor.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Emby.Server.Core/IO/LibraryMonitor.cs b/Emby.Server.Core/IO/LibraryMonitor.cs index 0f6a2e9a2c..8af826c881 100644 --- a/Emby.Server.Core/IO/LibraryMonitor.cs +++ b/Emby.Server.Core/IO/LibraryMonitor.cs @@ -294,6 +294,15 @@ namespace Emby.Server.Core.IO return; } + if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows) + { + if (path.StartsWith("\\\\", StringComparison.OrdinalIgnoreCase) || path.StartsWith("smb://", StringComparison.OrdinalIgnoreCase)) + { + // not supported + return; + } + } + // Already being watched if (_fileSystemWatchers.ContainsKey(path)) { From 5babf400231553e5904c64ed6ea6953d93e1afc3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 8 May 2017 14:06:36 -0400 Subject: [PATCH 05/37] update plugin uninstall --- .../Updates/InstallationManager.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 57019cc4e2..e7aa402f25 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -664,9 +664,19 @@ namespace Emby.Server.Implementations.Updates // Remove it the quick way for now _applicationHost.RemovePlugin(plugin); - _logger.Info("Deleting plugin file {0}", plugin.AssemblyFilePath); + var path = plugin.AssemblyFilePath; + _logger.Info("Deleting plugin file {0}", path); - _fileSystem.DeleteFile(plugin.AssemblyFilePath); + // Make this case-insensitive to account for possible incorrect assembly naming + var file = _fileSystem.GetFilePaths(path) + .FirstOrDefault(i => string.Equals(i, path, StringComparison.OrdinalIgnoreCase)); + + if (!string.IsNullOrWhiteSpace(file)) + { + path = file; + } + + _fileSystem.DeleteFile(path); OnPluginUninstalled(plugin); From ef41f919a6807949c0f91df5d82e56d0600a2194 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 8 May 2017 14:07:42 -0400 Subject: [PATCH 06/37] fix movie db find by external id --- MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs | 5 +---- .../TV/TheMovieDb/MovieDbSeriesProvider.cs | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 15221c2acd..27f66835f5 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -50,10 +50,7 @@ namespace MediaBrowser.MediaEncoding.Encoder return false; } - if (logOutput) - { - _logger.Info("ffmpeg info: {0}", output); - } + _logger.Info("ffmpeg info: {0}", output); if (output.IndexOf("Libav developers", StringComparison.OrdinalIgnoreCase) != -1) { diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs index f290247375..7bf926799f 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs @@ -443,7 +443,7 @@ namespace MediaBrowser.Providers.TV private async Task FindByExternalId(string id, string externalSource, CancellationToken cancellationToken) { - var url = string.Format("https://api.themoviedb.org/3/tv/find/{0}?api_key={1}&external_source={2}", + var url = string.Format("https://api.themoviedb.org/3/find/{0}?api_key={1}&external_source={2}", id, MovieDbProvider.ApiKey, externalSource); From ff03a018530c41fb5de4dd6932bd86d062d3f7ae Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 8 May 2017 14:07:57 -0400 Subject: [PATCH 07/37] 3.2.15.1 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 66e6eb3653..94ca1284bb 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.14.2")] +[assembly: AssemblyVersion("3.2.15.1")] From 198cb1bc9ccda757031963d01ef1f082da4a874f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 9 May 2017 14:51:26 -0400 Subject: [PATCH 08/37] update file responses --- .../IO/ManagedFileSystem.cs | 21 +++++- Emby.Drawing.Skia/Emby.Drawing.Skia.csproj | 65 ++++++++++++++++++ Emby.Drawing.Skia/Properties/AssemblyInfo.cs | 25 +++++++ Emby.Server.Core/ApplicationHost.cs | 3 +- .../HttpServer/HttpListenerHost.cs | 9 ++- .../HttpServer/HttpResultFactory.cs | 46 +++++-------- .../HttpServer/LoggerUtils.cs | 20 ++++-- .../SocketSharp/WebSocketSharpListener.cs | 7 +- .../SocketSharp/WebSocketSharpResponse.cs | 9 +++ .../Images/BaseDynamicImageProvider.cs | 2 +- .../Playback/BaseStreamingService.cs | 5 +- .../Configuration/ServerConfiguration.cs | 1 + MediaBrowser.Model/IO/IFileSystem.cs | 44 ++++++++++++ MediaBrowser.Model/Services/IRequest.cs | 2 + .../Manager/ProviderUtils.cs | 15 ++++ MediaBrowser.sln | 42 ++++++++++++ .../Net/EndPointListener.cs | 7 +- .../Net/EndPointManager.cs | 2 +- .../Net/HttpConnection.cs | 11 +-- .../Net/HttpListener.cs | 13 ++-- .../Net/ResponseStream.cs | 68 +++++++++++++++++-- 21 files changed, 358 insertions(+), 59 deletions(-) create mode 100644 Emby.Drawing.Skia/Emby.Drawing.Skia.csproj create mode 100644 Emby.Drawing.Skia/Properties/AssemblyInfo.cs diff --git a/Emby.Common.Implementations/IO/ManagedFileSystem.cs b/Emby.Common.Implementations/IO/ManagedFileSystem.cs index 3ed4f650f7..6cbf397585 100644 --- a/Emby.Common.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Common.Implementations/IO/ManagedFileSystem.cs @@ -392,10 +392,27 @@ namespace Emby.Common.Implementations.IO if (_supportsAsyncFileStreams && isAsync) { - return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), 262144, true); + return GetFileStream(path, mode, access, share, FileOpenOptions.Asynchronous); } - return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), 262144); + return GetFileStream(path, mode, access, share, FileOpenOptions.None); + } + + public Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, FileOpenOptions fileOpenOptions) + { + if (_sharpCifsFileSystem.IsEnabledForPath(path)) + { + return _sharpCifsFileSystem.GetFileStream(path, mode, access, share); + } + + var defaultBufferSize = 4096; + return new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), defaultBufferSize, GetFileOptions(fileOpenOptions)); + } + + private FileOptions GetFileOptions(FileOpenOptions mode) + { + var val = (int)mode; + return (FileOptions)val; } private FileMode GetFileMode(FileOpenMode mode) diff --git a/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj new file mode 100644 index 0000000000..b2a0e96076 --- /dev/null +++ b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj @@ -0,0 +1,65 @@ + + + + + 11.0 + Debug + AnyCPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD} + Library + Properties + Emby.Drawing.Skia + Emby.Drawing.Skia + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + v4.5 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + {9142eefa-7570-41e1-bfcc-468bb571af2f} + MediaBrowser.Common + + + {17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2} + MediaBrowser.Controller + + + {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} + MediaBrowser.Model + + + + + Properties\SharedVersion.cs + + + + + + \ No newline at end of file diff --git a/Emby.Drawing.Skia/Properties/AssemblyInfo.cs b/Emby.Drawing.Skia/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..c0dc7c5b4b --- /dev/null +++ b/Emby.Drawing.Skia/Properties/AssemblyInfo.cs @@ -0,0 +1,25 @@ +using System.Resources; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Emby.Drawing.Skia")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Emby.Drawing.Skia")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// \ No newline at end of file diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs index 78bdc11898..6a3881caf8 100644 --- a/Emby.Server.Core/ApplicationHost.cs +++ b/Emby.Server.Core/ApplicationHost.cs @@ -1132,7 +1132,8 @@ namespace Emby.Server.Core // Custom cert return new CertificateInfo { - Path = ServerConfigurationManager.Configuration.CertificatePath + Path = ServerConfigurationManager.Configuration.CertificatePath, + Password = ServerConfigurationManager.Configuration.CertificatePassword }; } diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index ee5245a69a..5e96eda94a 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -228,7 +228,8 @@ namespace Emby.Server.Implementations.HttpServer _streamFactory, _enableDualModeSockets, GetRequest, - _fileSystem); + _fileSystem, + _environment); } private IHttpRequest GetRequest(HttpListenerContext httpContext) @@ -452,6 +453,7 @@ namespace Emby.Server.Implementations.HttpServer var date = DateTime.Now; var httpRes = httpReq.Response; bool enableLog = false; + bool logHeaders = false; string urlToLog = null; string remoteIp = null; @@ -490,13 +492,14 @@ namespace Emby.Server.Implementations.HttpServer var urlString = url.OriginalString; enableLog = EnableLogging(urlString, localPath); urlToLog = urlString; + logHeaders = enableLog && urlToLog.IndexOf("/videos/", StringComparison.OrdinalIgnoreCase) != -1; if (enableLog) { urlToLog = GetUrlToLog(urlString); remoteIp = httpReq.RemoteIp; - LoggerUtils.LogRequest(_logger, urlToLog, httpReq.HttpMethod, httpReq.UserAgent); + LoggerUtils.LogRequest(_logger, urlToLog, httpReq.HttpMethod, httpReq.UserAgent, logHeaders ? httpReq.Headers : null); } if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) || @@ -611,7 +614,7 @@ namespace Emby.Server.Implementations.HttpServer var duration = DateTime.Now - date; - LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration); + LoggerUtils.LogResponse(_logger, statusCode, urlToLog, remoteIp, duration, logHeaders ? httpRes.Headers : null); } } } diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 687bd62b06..0af88595f9 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -353,31 +353,28 @@ namespace Emby.Server.Implementations.HttpServer /// /// Pres the process optimized result. /// - /// The request context. - /// The responseHeaders. - /// The cache key. - /// The cache key string. - /// The last date modified. - /// Duration of the cache. - /// Type of the content. - /// System.Object. private object GetCachedResult(IRequest requestContext, IDictionary responseHeaders, Guid cacheKey, string cacheKeyString, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType) { responseHeaders["ETag"] = string.Format("\"{0}\"", cacheKeyString); - if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration)) + var noCache = (requestContext.Headers.Get("Cache-Control") ?? string.Empty).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1; + + if (!noCache) { - AddAgeHeader(responseHeaders, lastDateModified); - AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration); + if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration)) + { + AddAgeHeader(responseHeaders, lastDateModified); + AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration, noCache); - var result = new HttpResult(new byte[] { }, contentType ?? "text/html", HttpStatusCode.NotModified); + var result = new HttpResult(new byte[] { }, contentType ?? "text/html", HttpStatusCode.NotModified); - AddResponseHeaders(result, responseHeaders); + AddResponseHeaders(result, responseHeaders); - return result; + return result; + } } - AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration); + AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration, noCache); return null; } @@ -673,11 +670,7 @@ namespace Emby.Server.Implementations.HttpServer /// /// Adds the caching responseHeaders. /// - /// The responseHeaders. - /// The cache key. - /// The last date modified. - /// Duration of the cache. - private void AddCachingHeaders(IDictionary responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration) + private void AddCachingHeaders(IDictionary responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, bool noCache) { // Don't specify both last modified and Etag, unless caching unconditionally. They are redundant // https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching @@ -687,11 +680,11 @@ namespace Emby.Server.Implementations.HttpServer responseHeaders["Last-Modified"] = lastDateModified.Value.ToString("r"); } - if (cacheDuration.HasValue) + if (!noCache && cacheDuration.HasValue) { responseHeaders["Cache-Control"] = "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds); } - else if (!string.IsNullOrEmpty(cacheKey)) + else if (!noCache && !string.IsNullOrEmpty(cacheKey)) { responseHeaders["Cache-Control"] = "public"; } @@ -701,18 +694,15 @@ namespace Emby.Server.Implementations.HttpServer responseHeaders["pragma"] = "no-cache, no-store, must-revalidate"; } - AddExpiresHeader(responseHeaders, cacheKey, cacheDuration); + AddExpiresHeader(responseHeaders, cacheKey, cacheDuration, noCache); } /// /// Adds the expires header. /// - /// The responseHeaders. - /// The cache key. - /// Duration of the cache. - private void AddExpiresHeader(IDictionary responseHeaders, string cacheKey, TimeSpan? cacheDuration) + private void AddExpiresHeader(IDictionary responseHeaders, string cacheKey, TimeSpan? cacheDuration, bool noCache) { - if (cacheDuration.HasValue) + if (!noCache && cacheDuration.HasValue) { responseHeaders["Expires"] = DateTime.UtcNow.Add(cacheDuration.Value).ToString("r"); } diff --git a/Emby.Server.Implementations/HttpServer/LoggerUtils.cs b/Emby.Server.Implementations/HttpServer/LoggerUtils.cs index 8fc92a09a7..f0e75eea48 100644 --- a/Emby.Server.Implementations/HttpServer/LoggerUtils.cs +++ b/Emby.Server.Implementations/HttpServer/LoggerUtils.cs @@ -1,6 +1,8 @@ using MediaBrowser.Model.Logging; using System; using System.Globalization; +using System.Linq; +using MediaBrowser.Model.Services; using SocketHttpListener.Net; namespace Emby.Server.Implementations.HttpServer @@ -19,9 +21,18 @@ namespace Emby.Server.Implementations.HttpServer logger.Info("{0} {1}. UserAgent: {2}", request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, url, request.UserAgent ?? string.Empty); } - public static void LogRequest(ILogger logger, string url, string method, string userAgent) + public static void LogRequest(ILogger logger, string url, string method, string userAgent, QueryParamCollection headers) { - logger.Info("{0} {1}. UserAgent: {2}", "HTTP " + method, url, userAgent ?? string.Empty); + if (headers == null) + { + logger.Info("{0} {1}. UserAgent: {2}", "HTTP " + method, url, userAgent ?? string.Empty); + } + else + { + var headerText = string.Join(", ", headers.Select(i => i.Name + "=" + i.Value).ToArray()); + + logger.Info("HTTP {0} {1}. {2}", method, url, headerText); + } } /// @@ -32,12 +43,13 @@ namespace Emby.Server.Implementations.HttpServer /// The URL. /// The end point. /// The duration. - public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration) + public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration, QueryParamCollection headers) { var durationMs = duration.TotalMilliseconds; var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms"; - logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url); + var headerText = headers == null ? string.Empty : "Headers: " + string.Join(", ", headers.Where(i => i.Name.IndexOf("Access-", StringComparison.OrdinalIgnoreCase) == -1).Select(i => i.Name + "=" + i.Value).ToArray()); + logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4} {5}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url, headerText); } } } diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs index b11b2fe88f..682fa7a0b8 100644 --- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs @@ -10,6 +10,7 @@ using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using MediaBrowser.Model.Services; +using MediaBrowser.Model.System; using MediaBrowser.Model.Text; using SocketHttpListener.Primitives; @@ -30,8 +31,9 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp private readonly IFileSystem _fileSystem; private readonly Func _httpRequestFactory; private readonly bool _enableDualMode; + private readonly IEnvironmentInfo _environment; - public WebSocketSharpListener(ILogger logger, ICertificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, bool enableDualMode, Func httpRequestFactory, IFileSystem fileSystem) + public WebSocketSharpListener(ILogger logger, ICertificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, bool enableDualMode, Func httpRequestFactory, IFileSystem fileSystem, IEnvironmentInfo environment) { _logger = logger; _certificate = certificate; @@ -44,6 +46,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp _enableDualMode = enableDualMode; _httpRequestFactory = httpRequestFactory; _fileSystem = fileSystem; + _environment = environment; } public Action ErrorHandler { get; set; } @@ -56,7 +59,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp public void Start(IEnumerable urlPrefixes) { if (_listener == null) - _listener = new HttpListener(_logger, _cryptoProvider, _streamFactory, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider, _fileSystem); + _listener = new HttpListener(_logger, _cryptoProvider, _streamFactory, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider, _fileSystem, _environment); _listener.EnableDualMode = _enableDualMode; diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs index fd30b227f0..9e58ee57cd 100644 --- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs +++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Services; using SocketHttpListener.Net; using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse; using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse; @@ -66,6 +67,14 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp _response.AddHeader(name, value); } + public QueryParamCollection Headers + { + get + { + return _response.Headers; + } + } + public string GetHeader(string name) { return _response.Headers[name]; diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs index 2677f7b2ad..b2ec84a82a 100644 --- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs +++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs @@ -258,7 +258,7 @@ namespace Emby.Server.Implementations.Images { return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); } - if (item is Playlist || item is MusicGenre || item is Genre || item is GameGenre) + if (item is Playlist || item is MusicGenre || item is Genre || item is GameGenre || item is PhotoAlbum) { return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); } diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index daec00e10b..67921ab348 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -671,12 +671,15 @@ namespace MediaBrowser.Api.Playback request.AudioCodec = EncodingHelper.InferAudioCodec(url); } + var enableDlnaHeaders = !string.IsNullOrWhiteSpace(request.Params) /*|| + string.Equals(Request.Headers.Get("GetContentFeatures.DLNA.ORG"), "1", StringComparison.OrdinalIgnoreCase)*/; + var state = new StreamState(MediaSourceManager, Logger, TranscodingJobType) { Request = request, RequestedUrl = url, UserAgent = Request.UserAgent, - EnableDlnaHeaders = !string.IsNullOrWhiteSpace(request.Params) + EnableDlnaHeaders = enableDlnaHeaders }; var auth = AuthorizationContext.GetAuthorizationInfo(Request); diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 838111a383..60bbf62404 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -55,6 +55,7 @@ namespace MediaBrowser.Model.Configuration /// /// The value pointing to the file system where the ssl certiifcate is located.. public string CertificatePath { get; set; } + public string CertificatePassword { get; set; } /// /// Gets or sets a value indicating whether this instance is port authorized. diff --git a/MediaBrowser.Model/IO/IFileSystem.cs b/MediaBrowser.Model/IO/IFileSystem.cs index 26de9332e3..92112f4ae3 100644 --- a/MediaBrowser.Model/IO/IFileSystem.cs +++ b/MediaBrowser.Model/IO/IFileSystem.cs @@ -108,6 +108,8 @@ namespace MediaBrowser.Model.IO /// FileStream. Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, bool isAsync = false); + Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, FileOpenOptions fileOpenOptions); + /// /// Opens the read. /// @@ -402,4 +404,46 @@ namespace MediaBrowser.Model.IO ReadWrite = 3 } + // + // Summary: + // Represents advanced options for creating a System.IO.FileStream object. + [Flags] + public enum FileOpenOptions + { + // + // Summary: + // Indicates that the system should write through any intermediate cache and go + // directly to disk. + WriteThrough = int.MinValue, + // + // Summary: + // Indicates that no additional options should be used when creating a System.IO.FileStream + // object. + None = 0, + // + // Summary: + // Indicates that a file is encrypted and can be decrypted only by using the same + // user account used for encryption. + Encrypted = 16384, + // + // Summary: + // Indicates that a file is automatically deleted when it is no longer in use. + DeleteOnClose = 67108864, + // + // Summary: + // Indicates that the file is to be accessed sequentially from beginning to end. + // The system can use this as a hint to optimize file caching. If an application + // moves the file pointer for random access, optimum caching may not occur; however, + // correct operation is still guaranteed. + SequentialScan = 134217728, + // + // Summary: + // Indicates that the file is accessed randomly. The system can use this as a hint + // to optimize file caching. + RandomAccess = 268435456, + // + // Summary: + // Indicates that a file can be used for asynchronous reading and writing. + Asynchronous = 1073741824 + } } diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs index 115ba25ce0..f056c7410a 100644 --- a/MediaBrowser.Model/Services/IRequest.cs +++ b/MediaBrowser.Model/Services/IRequest.cs @@ -155,6 +155,8 @@ namespace MediaBrowser.Model.Services //Add Metadata to Response Dictionary Items { get; } + QueryParamCollection Headers { get; } + Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs index f544c09dc1..d5494c21fd 100644 --- a/MediaBrowser.Providers/Manager/ProviderUtils.cs +++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs @@ -200,6 +200,7 @@ namespace MediaBrowser.Providers.Manager MergeCriticRating(source, target, lockedFields, replaceData); MergeAwards(source, target, lockedFields, replaceData); MergeTrailers(source, target, lockedFields, replaceData); + MergeVideoInfo(source, target, lockedFields, replaceData); if (mergeMetadataSettings) { @@ -307,5 +308,19 @@ namespace MediaBrowser.Providers.Manager } } } + + private static void MergeVideoInfo(BaseItem source, BaseItem target, List lockedFields, bool replaceData) + { + var sourceCast = source as Video; + var targetCast = target as Video; + + if (sourceCast != null && targetCast != null) + { + if (replaceData || targetCast.Video3DFormat == null) + { + targetCast.Video3DFormat = sourceCast.Video3DFormat; + } + } + } } } diff --git a/MediaBrowser.sln b/MediaBrowser.sln index b9933969f5..219beeab16 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -80,6 +80,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing.Net", "Emby.Dr EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketHttpListener.Portable", "SocketHttpListener.Portable\SocketHttpListener.Portable.csproj", "{4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing.Skia", "Emby.Drawing.Skia\Emby.Drawing.Skia.csproj", "{2312DA6D-FF86-4597-9777-BCEEC32D96DD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1099,6 +1101,46 @@ Global {4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}.Signed|x64.Build.0 = Release|Any CPU {4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}.Signed|x86.ActiveCfg = Release|Any CPU {4F26D5D8-A7B0-42B3-BA42-7CB7D245934E}.Signed|x86.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Win32.ActiveCfg = Debug|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|Win32.Build.0 = Debug|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|x64.ActiveCfg = Debug|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|x64.Build.0 = Debug|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|x86.ActiveCfg = Debug|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Debug|x86.Build.0 = Debug|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Any CPU.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Mixed Platforms.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Mixed Platforms.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Win32.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|Win32.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|x64.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|x64.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|x86.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release Mono|x86.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Any CPU.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Win32.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|Win32.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|x64.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|x64.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|x86.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Release|x86.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Any CPU.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Any CPU.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Mixed Platforms.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Mixed Platforms.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Win32.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|Win32.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x64.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x64.Build.0 = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x86.ActiveCfg = Release|Any CPU + {2312DA6D-FF86-4597-9777-BCEEC32D96DD}.Signed|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SocketHttpListener.Portable/Net/EndPointListener.cs b/SocketHttpListener.Portable/Net/EndPointListener.cs index 4f1a17fc0d..2106bbec56 100644 --- a/SocketHttpListener.Portable/Net/EndPointListener.cs +++ b/SocketHttpListener.Portable/Net/EndPointListener.cs @@ -8,6 +8,7 @@ using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; +using MediaBrowser.Model.System; using MediaBrowser.Model.Text; using SocketHttpListener.Primitives; @@ -33,8 +34,9 @@ namespace SocketHttpListener.Net private readonly ITextEncoding _textEncoding; private readonly IMemoryStreamFactory _memoryStreamFactory; private readonly IFileSystem _fileSystem; + private readonly IEnvironmentInfo _environment; - public EndPointListener(HttpListener listener, IpAddressInfo addr, int port, bool secure, ICertificate cert, ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem) + public EndPointListener(HttpListener listener, IpAddressInfo addr, int port, bool secure, ICertificate cert, ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) { this.listener = listener; _logger = logger; @@ -44,6 +46,7 @@ namespace SocketHttpListener.Net _memoryStreamFactory = memoryStreamFactory; _textEncoding = textEncoding; _fileSystem = fileSystem; + _environment = environment; this.secure = secure; this.cert = cert; @@ -109,7 +112,7 @@ namespace SocketHttpListener.Net return; } - HttpConnection conn = await HttpConnection.Create(_logger, accepted, listener, listener.secure, listener.cert, _cryptoProvider, _streamFactory, _memoryStreamFactory, _textEncoding, _fileSystem).ConfigureAwait(false); + HttpConnection conn = await HttpConnection.Create(_logger, accepted, listener, listener.secure, listener.cert, _cryptoProvider, _streamFactory, _memoryStreamFactory, _textEncoding, _fileSystem, _environment).ConfigureAwait(false); //_logger.Debug("Adding unregistered connection to {0}. Id: {1}", accepted.RemoteEndPoint, connectionId); lock (listener.unregistered) diff --git a/SocketHttpListener.Portable/Net/EndPointManager.cs b/SocketHttpListener.Portable/Net/EndPointManager.cs index 11f7749153..6a00ed360a 100644 --- a/SocketHttpListener.Portable/Net/EndPointManager.cs +++ b/SocketHttpListener.Portable/Net/EndPointManager.cs @@ -106,7 +106,7 @@ namespace SocketHttpListener.Net } else { - epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.StreamFactory, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem); + epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.StreamFactory, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem, listener.EnvironmentInfo); p[port] = epl; } diff --git a/SocketHttpListener.Portable/Net/HttpConnection.cs b/SocketHttpListener.Portable/Net/HttpConnection.cs index ac8ada4862..65e7470f7e 100644 --- a/SocketHttpListener.Portable/Net/HttpConnection.cs +++ b/SocketHttpListener.Portable/Net/HttpConnection.cs @@ -6,6 +6,7 @@ using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; +using MediaBrowser.Model.System; using MediaBrowser.Model.Text; using SocketHttpListener.Primitives; @@ -41,8 +42,9 @@ namespace SocketHttpListener.Net private readonly ITextEncoding _textEncoding; private readonly IStreamFactory _streamFactory; private readonly IFileSystem _fileSystem; + private readonly IEnvironmentInfo _environment; - private HttpConnection(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem) + private HttpConnection(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) { _logger = logger; this.sock = sock; @@ -53,6 +55,7 @@ namespace SocketHttpListener.Net _memoryStreamFactory = memoryStreamFactory; _textEncoding = textEncoding; _fileSystem = fileSystem; + _environment = environment; _streamFactory = streamFactory; } @@ -84,9 +87,9 @@ namespace SocketHttpListener.Net Init(); } - public static async Task Create(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem) + public static async Task Create(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) { - var connection = new HttpConnection(logger, sock, epl, secure, cert, cryptoProvider, streamFactory, memoryStreamFactory, textEncoding, fileSystem); + var connection = new HttpConnection(logger, sock, epl, secure, cert, cryptoProvider, streamFactory, memoryStreamFactory, textEncoding, fileSystem, environment); await connection.InitStream().ConfigureAwait(false); @@ -217,7 +220,7 @@ namespace SocketHttpListener.Net { var supportsDirectSocketAccess = !context.Response.SendChunked && !isExpect100Continue && !secure; - o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding, _fileSystem, sock, supportsDirectSocketAccess, _logger); + o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding, _fileSystem, sock, supportsDirectSocketAccess, _logger, _environment); } else { diff --git a/SocketHttpListener.Portable/Net/HttpListener.cs b/SocketHttpListener.Portable/Net/HttpListener.cs index c2e7acd8e7..b3e01425ca 100644 --- a/SocketHttpListener.Portable/Net/HttpListener.cs +++ b/SocketHttpListener.Portable/Net/HttpListener.cs @@ -8,6 +8,7 @@ using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; +using MediaBrowser.Model.System; using MediaBrowser.Model.Text; using SocketHttpListener.Primitives; @@ -22,6 +23,7 @@ namespace SocketHttpListener.Net internal ITextEncoding TextEncoding { get; private set; } internal IMemoryStreamFactory MemoryStreamFactory { get; private set; } internal INetworkManager NetworkManager { get; private set; } + internal IEnvironmentInfo EnvironmentInfo { get; private set; } public bool EnableDualMode { get; set; } @@ -40,7 +42,7 @@ namespace SocketHttpListener.Net public Action OnContext { get; set; } - public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem) + public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo) { _logger = logger; CryptoProvider = cryptoProvider; @@ -50,19 +52,20 @@ namespace SocketHttpListener.Net TextEncoding = textEncoding; MemoryStreamFactory = memoryStreamFactory; FileSystem = fileSystem; + EnvironmentInfo = environmentInfo; prefixes = new HttpListenerPrefixCollection(logger, this); registry = new Dictionary(); connections = new Dictionary(); auth_schemes = AuthenticationSchemes.Anonymous; } - public HttpListener(ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem) - :this(new NullLogger(), certificate, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem) + public HttpListener(ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo) + :this(new NullLogger(), certificate, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo) { } - public HttpListener(ILogger logger, ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem) - : this(logger, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem) + public HttpListener(ILogger logger, ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo) + : this(logger, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo) { _certificate = certificate; } diff --git a/SocketHttpListener.Portable/Net/ResponseStream.cs b/SocketHttpListener.Portable/Net/ResponseStream.cs index dea4049d56..9552fe8ca0 100644 --- a/SocketHttpListener.Portable/Net/ResponseStream.cs +++ b/SocketHttpListener.Portable/Net/ResponseStream.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; +using MediaBrowser.Model.System; using MediaBrowser.Model.Text; using SocketHttpListener.Primitives; @@ -28,8 +29,9 @@ namespace SocketHttpListener.Net private readonly IAcceptSocket _socket; private readonly bool _supportsDirectSocketAccess; private readonly ILogger _logger; + private readonly IEnvironmentInfo _environment; - internal ResponseStream(Stream stream, HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IAcceptSocket socket, bool supportsDirectSocketAccess, ILogger logger) + internal ResponseStream(Stream stream, HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IAcceptSocket socket, bool supportsDirectSocketAccess, ILogger logger, IEnvironmentInfo environment) { this.response = response; _memoryStreamFactory = memoryStreamFactory; @@ -38,6 +40,7 @@ namespace SocketHttpListener.Net _socket = socket; _supportsDirectSocketAccess = supportsDirectSocketAccess; _logger = logger; + _environment = environment; this.stream = stream; } @@ -344,7 +347,20 @@ namespace SocketHttpListener.Net private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) { - using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, true)) + var allowAsync = _environment.OperatingSystem != OperatingSystem.Windows; + + var fileOpenOptions = offset > 0 + ? FileOpenOptions.RandomAccess + : FileOpenOptions.SequentialScan; + + if (allowAsync) + { + fileOpenOptions |= FileOpenOptions.Asynchronous; + } + + // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 + + using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, fileOpenOptions)) { if (offset > 0) { @@ -355,11 +371,53 @@ namespace SocketHttpListener.Net if (count > 0) { - await CopyToInternalAsync(fs, targetStream, count, cancellationToken).ConfigureAwait(false); + if (allowAsync) + { + await CopyToInternalAsync(fs, targetStream, count, cancellationToken).ConfigureAwait(false); + } + else + { + await CopyToInternalAsyncWithSyncRead(fs, targetStream, count, cancellationToken).ConfigureAwait(false); + } } else { - await fs.CopyToAsync(targetStream, 81920, cancellationToken).ConfigureAwait(false); + if (allowAsync) + { + await fs.CopyToAsync(targetStream, 81920, cancellationToken).ConfigureAwait(false); + } + else + { + fs.CopyTo(targetStream, 81920); + } + } + } + } + + private static async Task CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) + { + var array = new byte[81920]; + int bytesRead; + + while ((bytesRead = source.Read(array, 0, array.Length)) != 0) + { + if (bytesRead == 0) + { + break; + } + + var bytesToWrite = Math.Min(bytesRead, copyLength); + + if (bytesToWrite > 0) + { + await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); + } + + copyLength -= bytesToWrite; + + if (copyLength <= 0) + { + break; } } } @@ -368,7 +426,7 @@ namespace SocketHttpListener.Net { var array = new byte[81920]; int bytesRead; - + while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0) { if (bytesRead == 0) From 51312b8570cce4862ebbbbe03c6a888808603421 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 9 May 2017 14:53:50 -0400 Subject: [PATCH 09/37] update nuget --- Emby.Common.Implementations/project.json | 2 +- Emby.Server.Core/project.json | 2 +- .../Emby.Server.Implementations.csproj | 2 +- Emby.Server.Implementations/packages.config | 2 +- MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj | 4 ++-- MediaBrowser.Server.Mono/packages.config | 4 ++-- .../MediaBrowser.ServerApplication.csproj | 4 ++-- MediaBrowser.ServerApplication/packages.config | 4 ++-- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Emby.Common.Implementations/project.json b/Emby.Common.Implementations/project.json index 674101e8a7..ff60c740e8 100644 --- a/Emby.Common.Implementations/project.json +++ b/Emby.Common.Implementations/project.json @@ -45,7 +45,7 @@ "System.Net.Requests": "4.3.0", "System.Xml.ReaderWriter": "4.3.0", "System.Xml.XmlSerializer": "4.3.0", - "System.Net.Http": "4.3.0", + "System.Net.Http": "4.3.2", "System.Net.Primitives": "4.3.0", "System.Net.Sockets": "4.3.0", "System.Net.NetworkInformation": "4.3.0", diff --git a/Emby.Server.Core/project.json b/Emby.Server.Core/project.json index 70543d7df1..fd4f9d6cf7 100644 --- a/Emby.Server.Core/project.json +++ b/Emby.Server.Core/project.json @@ -68,7 +68,7 @@ "System.AppDomain": "2.0.11", "System.Globalization.Extensions": "4.3.0", "System.IO.FileSystem.Watcher": "4.3.0", - "System.Net.Security": "4.3.0", + "System.Net.Security": "4.3.1", "System.Security.Cryptography.X509Certificates": "4.3.0", "System.Runtime.Extensions": "4.3.0", "MediaBrowser.Model": { diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index d4766e1ec7..b2f1f0ceb6 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -308,7 +308,7 @@ True - ..\packages\SQLitePCLRaw.core.1.1.2\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.core.dll + ..\packages\SQLitePCLRaw.core.1.1.5\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.core.dll True diff --git a/Emby.Server.Implementations/packages.config b/Emby.Server.Implementations/packages.config index e4c75e1e92..5ce754d3ff 100644 --- a/Emby.Server.Implementations/packages.config +++ b/Emby.Server.Implementations/packages.config @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj index bcdfa858ff..e4bde07c7d 100644 --- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj +++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj @@ -94,11 +94,11 @@ True - ..\packages\SQLitePCLRaw.core.1.1.2\lib\net45\SQLitePCLRaw.core.dll + ..\packages\SQLitePCLRaw.core.1.1.5\lib\net45\SQLitePCLRaw.core.dll True - ..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.2\lib\net45\SQLitePCLRaw.provider.sqlite3.dll + ..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.5\lib\net45\SQLitePCLRaw.provider.sqlite3.dll True diff --git a/MediaBrowser.Server.Mono/packages.config b/MediaBrowser.Server.Mono/packages.config index 81da308f52..de26c7666e 100644 --- a/MediaBrowser.Server.Mono/packages.config +++ b/MediaBrowser.Server.Mono/packages.config @@ -5,6 +5,6 @@ - - + + \ No newline at end of file diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index 749468fe2b..89e28eeb2e 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -100,11 +100,11 @@ True - ..\packages\SQLitePCLRaw.core.1.1.2\lib\net45\SQLitePCLRaw.core.dll + ..\packages\SQLitePCLRaw.core.1.1.5\lib\net45\SQLitePCLRaw.core.dll True - ..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.2\lib\net45\SQLitePCLRaw.provider.sqlite3.dll + ..\packages\SQLitePCLRaw.provider.sqlite3.net45.1.1.5\lib\net45\SQLitePCLRaw.provider.sqlite3.dll True diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config index 68d0a7fdad..04e4e0f973 100644 --- a/MediaBrowser.ServerApplication/packages.config +++ b/MediaBrowser.ServerApplication/packages.config @@ -5,6 +5,6 @@ - - + + \ No newline at end of file From 0251e41935a715e2dc092a2a904fe754b9822f1c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 9 May 2017 15:06:39 -0400 Subject: [PATCH 10/37] add skia sharp --- Emby.Drawing.Skia/Emby.Drawing.Skia.csproj | 9 +++++++++ Emby.Drawing.Skia/packages.config | 4 ++++ .../MediaBrowser.ServerApplication.csproj | 11 +++++++++++ MediaBrowser.ServerApplication/packages.config | 1 + 4 files changed, 25 insertions(+) create mode 100644 Emby.Drawing.Skia/packages.config diff --git a/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj index b2a0e96076..8d1e221d0a 100644 --- a/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj +++ b/Emby.Drawing.Skia/Emby.Drawing.Skia.csproj @@ -54,6 +54,15 @@ + + + ..\packages\SkiaSharp.1.57.1\lib\portable-net45+win8+wpa81+wp8\SkiaSharp.dll + True + + + + +