瀏覽代碼

Merge pull request #325 from jellyfin/dev

Master 3.5.2-5
Joshua M. Boniface 6 年之前
父節點
當前提交
76b647e0a8
共有 75 個文件被更改,包括 839 次插入432 次删除
  1. 1 0
      .gitattributes
  2. 0 68
      Build-JellyFin.ps1
  3. 0 4
      CODE_OF_CONDUCT.md
  4. 3 0
      CONTRIBUTORS.md
  5. 10 10
      Emby.Dlna/ContentDirectory/ControlHandler.cs
  6. 1 1
      Emby.Dlna/Didl/DidlBuilder.cs
  7. 1 1
      Emby.Dlna/PlayTo/Device.cs
  8. 1 1
      Emby.Dlna/PlayTo/PlayToController.cs
  9. 1 1
      Emby.Dlna/Profiles/DefaultProfile.cs
  10. 1 1
      Emby.Dlna/Service/BaseControlHandler.cs
  11. 2 2
      Emby.Drawing/ImageProcessor.cs
  12. 1 1
      Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
  13. 4 4
      Emby.Server.Implementations/Activity/ActivityRepository.cs
  14. 31 6
      Emby.Server.Implementations/ApplicationHost.cs
  15. 4 4
      Emby.Server.Implementations/Channels/ChannelManager.cs
  16. 1 1
      Emby.Server.Implementations/Collections/CollectionManager.cs
  17. 16 16
      Emby.Server.Implementations/Data/SqliteItemRepository.cs
  18. 2 2
      Emby.Server.Implementations/Devices/DeviceManager.cs
  19. 1 1
      Emby.Server.Implementations/Dto/DtoService.cs
  20. 2 3
      Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
  21. 1 1
      Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs
  22. 2 2
      Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
  23. 8 5
      Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
  24. 1 0
      Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Collections.cs
  25. 3 3
      Emby.Server.Implementations/Library/LibraryManager.cs
  26. 2 2
      Emby.Server.Implementations/Library/SearchEngine.cs
  27. 1 1
      Emby.Server.Implementations/Library/UserViewManager.cs
  28. 1 1
      Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
  29. 11 11
      Emby.Server.Implementations/LiveTv/LiveTvManager.cs
  30. 1 1
      Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
  31. 1 1
      Emby.Server.Implementations/Networking/NetworkManager.cs
  32. 2 2
      Emby.Server.Implementations/Playlists/PlaylistManager.cs
  33. 1 1
      Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
  34. 0 142
      Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs
  35. 2 3
      Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
  36. 2 2
      Emby.Server.Implementations/Security/AuthenticationRepository.cs
  37. 2 2
      Emby.Server.Implementations/Services/ServiceExec.cs
  38. 5 5
      Emby.Server.Implementations/Services/ServicePath.cs
  39. 5 5
      Emby.Server.Implementations/Session/SessionManager.cs
  40. 2 2
      MediaBrowser.Api/BaseApiService.cs
  41. 2 2
      MediaBrowser.Api/LiveTv/LiveTvService.cs
  42. 6 6
      MediaBrowser.Api/Movies/MoviesService.cs
  43. 1 2
      MediaBrowser.Api/SimilarItemsHelper.cs
  44. 1 1
      MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
  45. 1 1
      MediaBrowser.Api/UserLibrary/UserViewsService.cs
  46. 10 25
      MediaBrowser.Controller/Entities/BaseItem.cs
  47. 42 0
      MediaBrowser.Controller/Entities/BaseItemExtensions.cs
  48. 1 1
      MediaBrowser.Controller/Entities/CollectionFolder.cs
  49. 1 4
      MediaBrowser.Controller/Entities/Extensions.cs
  50. 2 2
      MediaBrowser.Controller/Entities/Folder.cs
  51. 1 6
      MediaBrowser.Controller/Entities/TagExtensions.cs
  52. 1 2
      MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs
  53. 1 1
      MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs
  54. 10 23
      MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
  55. 2 2
      MediaBrowser.Model/Configuration/ServerConfiguration.cs
  56. 1 1
      MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs
  57. 1 1
      MediaBrowser.Model/Dlna/StreamInfo.cs
  58. 4 3
      MediaBrowser.Model/Entities/MediaStream.cs
  59. 1 13
      MediaBrowser.Model/Extensions/LinqExtensions.cs
  60. 1 3
      MediaBrowser.Model/Services/HttpUtility.cs
  61. 1 2
      MediaBrowser.Model/Services/QueryParamCollection.cs
  62. 1 1
      MediaBrowser.Providers/Manager/ImageSaver.cs
  63. 2 2
      MediaBrowser.Providers/Manager/ProviderManager.cs
  64. 1 1
      MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
  65. 1 1
      MediaBrowser.Providers/Movies/MovieDbProvider.cs
  66. 1 2
      MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
  67. 1 1
      MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs
  68. 1 1
      Mono.Nat/Pmp/PmpNatDevice.cs
  69. 110 0
      build-jellyfin.ps1
  70. 7 0
      debian/changelog
  71. 2 2
      debian/jellyfin.service
  72. 2 1
      debian/rules
  73. 460 0
      install-jellyfin.ps1
  74. 1 0
      install.bat
  75. 22 0
      new-file-header.txt

+ 1 - 0
.gitattributes

@@ -0,0 +1 @@
+CONTRIBUTORS.md merge=union

+ 0 - 68
Build-JellyFin.ps1

@@ -1,68 +0,0 @@
-[CmdletBinding()]
-param(
-    [switch]$InstallFFMPEG,
-    [switch]$GenerateZip,
-    [string]$InstallLocation = "$Env:AppData/JellyFin-Server/",
-    [ValidateSet('Debug','Release')][string]$BuildType = 'Release',
-    [ValidateSet('Quiet','Minimal', 'Normal')][string]$DotNetVerbosity = 'Minimal',
-    [ValidateSet('win','win7', 'win8','win81','win10')][string]$WindowsVersion = 'win',
-    [ValidateSet('x64','x86', 'arm', 'arm64')][string]$Architecture = 'x64'
-)
-function Build-JellyFin {
-    if($Architecture -eq 'arm64'){
-        if($WindowsVersion -ne 'win10'){
-            Write-Error "arm64 only supported with Windows10 Version"
-            exit
-        }
-    }
-    if($Architecture -eq 'arm'){
-        if($WindowsVersion -notin @('win10','win81','win8')){
-            Write-Error "arm only supported with Windows 8 or higher"
-            exit
-        }
-    }
-    dotnet publish -c $BuildType -r "$windowsversion-$Architecture" MediaBrowser.sln -o $InstallLocation -v $DotNetVerbosity
-}
-
-function Install-FFMPEG {
-    param(
-        [string]$InstallLocation,
-        [string]$Architecture
-    )
-    Write-Verbose "Checking Architecture"
-    if($Architecture -notin @('x86','x64')){
-        Write-Warning "No builds available for your selected architecture of $Architecture"
-        Write-Warning "FFMPEG will not be installed" 
-    }elseif($Architecture -eq 'x64'){
-         Write-Verbose "Downloading 64 bit FFMPEG"
-         Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-4.1-win64-static.zip -UseBasicParsing -OutFile "$env:TEMP/fmmpeg.zip" | Write-Verbose
-    }else{
-         Write-Verbose "Downloading 32 bit FFMPEG"
-         Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-4.1-win32-static.zip -UseBasicParsing -OutFile "$env:TEMP/fmmpeg.zip" | Write-Verbose
-    }
-   
-    Expand-Archive "$env:TEMP/fmmpeg.zip" -DestinationPath "$env:TEMP/ffmpeg/" | Write-Verbose
-    if($Architecture -eq 'x64'){
-        Write-Verbose "Copying Binaries to Jellyfin location"
-        Get-ChildItem "$env:temp/ffmpeg/ffmpeg-4.1-win64-static/bin" | ForEach-Object {
-            Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
-        }
-    }else{
-        Write-Verbose "Copying Binaries to Jellyfin location"
-        Get-ChildItem "$env:temp/ffmpeg/ffmpeg-4.1-win32-static/bin" | ForEach-Object {
-            Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
-        }
-    }
-    Remove-Item "$env:TEMP/ffmpeg/" -Recurse -Force -ErrorAction Continue | Write-Verbose
-    Remove-Item "$env:TEMP/fmmpeg.zip" -Force -ErrorAction Continue | Write-Verbose
-}
-Write-Verbose "Starting Build Process: Selected Environment is $WindowsVersion-$Architecture"
-Build-JellyFin
-if($InstallFFMPEG.IsPresent -or ($InstallFFMPEG -eq $true)){
-    Write-Verbose "Starting FFMPEG Install"
-    Install-FFMPEG $InstallLocation $Architecture
-}
-if($GenerateZip.IsPresent -or ($GenerateZip -eq $true)){
-    Compress-Archive -Path $InstallLocation -DestinationPath "$InstallLocation/jellyfin.zip" -Force
-}
-Write-Verbose "Finished"

+ 0 - 4
CODE_OF_CONDUCT.md

@@ -1,4 +0,0 @@
-1. Don't sneakily relicense free software.
-2. Don't continually nag users to give you money.
-3. Don't hide binary blobs in otherwise free software.
-4. Don't needlessly obfuscate the build process or any other part of free software.

+ 3 - 0
CONTRIBUTORS.md

@@ -4,6 +4,9 @@
  - [nvllsvm](https://github.com/nvllsvm)
  - [nvllsvm](https://github.com/nvllsvm)
  - [JustAMan](https://github.com/JustAMan)
  - [JustAMan](https://github.com/JustAMan)
  - [dcrdev](https://github.com/dcrdev)
  - [dcrdev](https://github.com/dcrdev)
+ - [EraYaN](https://github.com/EraYaN)
+ - [flemse](https://github.com/flemse)
+ - [bfayers](https://github.com/bfayers)
 
 
 # Emby Contributors
 # Emby Contributors
 
 

+ 10 - 10
Emby.Dlna/ContentDirectory/ControlHandler.cs

@@ -467,7 +467,7 @@ namespace Emby.Dlna.ContentDirectory
                 IsMissing = false,
                 IsMissing = false,
                 ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
                 ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name },
                 IsFolder = isFolder,
                 IsFolder = isFolder,
-                MediaTypes = mediaTypes.ToArray(mediaTypes.Count),
+                MediaTypes = mediaTypes.ToArray(),
                 DtoOptions = GetDtoOptions()
                 DtoOptions = GetDtoOptions()
             });
             });
         }
         }
@@ -676,7 +676,7 @@ namespace Emby.Dlna.ContentDirectory
 
 
             return new QueryResult<ServerItem>
             return new QueryResult<ServerItem>
             {
             {
-                Items = list.ToArray(list.Count),
+                Items = list.ToArray(),
                 TotalRecordCount = list.Count
                 TotalRecordCount = list.Count
             };
             };
         }
         }
@@ -754,7 +754,7 @@ namespace Emby.Dlna.ContentDirectory
 
 
             return new QueryResult<ServerItem>
             return new QueryResult<ServerItem>
             {
             {
-                Items = list.ToArray(list.Count),
+                Items = list.ToArray(),
                 TotalRecordCount = list.Count
                 TotalRecordCount = list.Count
             };
             };
         }
         }
@@ -859,7 +859,7 @@ namespace Emby.Dlna.ContentDirectory
 
 
             return new QueryResult<ServerItem>
             return new QueryResult<ServerItem>
             {
             {
-                Items = list.ToArray(list.Count),
+                Items = list.ToArray(),
                 TotalRecordCount = list.Count
                 TotalRecordCount = list.Count
             };
             };
         }
         }
@@ -1026,7 +1026,7 @@ namespace Emby.Dlna.ContentDirectory
             var result = new QueryResult<BaseItem>
             var result = new QueryResult<BaseItem>
             {
             {
                 TotalRecordCount = genresResult.TotalRecordCount,
                 TotalRecordCount = genresResult.TotalRecordCount,
-                Items = genresResult.Items.Select(i => i.Item1).ToArray(genresResult.Items.Length)
+                Items = genresResult.Items.Select(i => i.Item1).ToArray()
             };
             };
 
 
             return ToResult(result);
             return ToResult(result);
@@ -1044,7 +1044,7 @@ namespace Emby.Dlna.ContentDirectory
             var result = new QueryResult<BaseItem>
             var result = new QueryResult<BaseItem>
             {
             {
                 TotalRecordCount = genresResult.TotalRecordCount,
                 TotalRecordCount = genresResult.TotalRecordCount,
-                Items = genresResult.Items.Select(i => i.Item1).ToArray(genresResult.Items.Length)
+                Items = genresResult.Items.Select(i => i.Item1).ToArray()
             };
             };
 
 
             return ToResult(result);
             return ToResult(result);
@@ -1062,7 +1062,7 @@ namespace Emby.Dlna.ContentDirectory
             var result = new QueryResult<BaseItem>
             var result = new QueryResult<BaseItem>
             {
             {
                 TotalRecordCount = artists.TotalRecordCount,
                 TotalRecordCount = artists.TotalRecordCount,
-                Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
+                Items = artists.Items.Select(i => i.Item1).ToArray()
             };
             };
 
 
             return ToResult(result);
             return ToResult(result);
@@ -1080,7 +1080,7 @@ namespace Emby.Dlna.ContentDirectory
             var result = new QueryResult<BaseItem>
             var result = new QueryResult<BaseItem>
             {
             {
                 TotalRecordCount = artists.TotalRecordCount,
                 TotalRecordCount = artists.TotalRecordCount,
-                Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
+                Items = artists.Items.Select(i => i.Item1).ToArray()
             };
             };
 
 
             return ToResult(result);
             return ToResult(result);
@@ -1099,7 +1099,7 @@ namespace Emby.Dlna.ContentDirectory
             var result = new QueryResult<BaseItem>
             var result = new QueryResult<BaseItem>
             {
             {
                 TotalRecordCount = artists.TotalRecordCount,
                 TotalRecordCount = artists.TotalRecordCount,
-                Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length)
+                Items = artists.Items.Select(i => i.Item1).ToArray()
             };
             };
 
 
             return ToResult(result);
             return ToResult(result);
@@ -1247,7 +1247,7 @@ namespace Emby.Dlna.ContentDirectory
         {
         {
             var serverItems = result
             var serverItems = result
                 .Select(i => new ServerItem(i))
                 .Select(i => new ServerItem(i))
-                .ToArray(result.Length);
+                .ToArray();
 
 
             return new QueryResult<ServerItem>
             return new QueryResult<ServerItem>
             {
             {

+ 1 - 1
Emby.Dlna/Didl/DidlBuilder.cs

@@ -512,7 +512,7 @@ namespace Emby.Dlna.Didl
                 streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions
                 streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions
                 {
                 {
                     ItemId = audio.Id,
                     ItemId = audio.Id,
-                    MediaSources = sources.ToArray(sources.Count),
+                    MediaSources = sources.ToArray(),
                     Profile = _profile,
                     Profile = _profile,
                     DeviceId = deviceId
                     DeviceId = deviceId
                 });
                 });

+ 1 - 1
Emby.Dlna/PlayTo/Device.cs

@@ -941,7 +941,7 @@ namespace Emby.Dlna.PlayTo
             if (room != null && !string.IsNullOrWhiteSpace(room.Value))
             if (room != null && !string.IsNullOrWhiteSpace(room.Value))
                 friendlyNames.Add(room.Value);
                 friendlyNames.Add(room.Value);
 
 
-            deviceProperties.Name = string.Join(" ", friendlyNames.ToArray(friendlyNames.Count));
+            deviceProperties.Name = string.Join(" ", friendlyNames.ToArray());
 
 
             var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault();
             var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault();
             if (model != null)
             if (model != null)

+ 1 - 1
Emby.Dlna/PlayTo/PlayToController.cs

@@ -571,7 +571,7 @@ namespace Emby.Dlna.PlayTo
                     StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildAudioItem(new AudioOptions
                     StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildAudioItem(new AudioOptions
                     {
                     {
                         ItemId = item.Id,
                         ItemId = item.Id,
-                        MediaSources = mediaSources.ToArray(mediaSources.Count),
+                        MediaSources = mediaSources.ToArray(),
                         Profile = profile,
                         Profile = profile,
                         DeviceId = deviceId,
                         DeviceId = deviceId,
                         MaxBitrate = profile.MaxStreamingBitrate,
                         MaxBitrate = profile.MaxStreamingBitrate,

+ 1 - 1
Emby.Dlna/Profiles/DefaultProfile.cs

@@ -173,7 +173,7 @@ namespace Emby.Dlna.Profiles
                 Value = value
                 Value = value
             });
             });
 
 
-            XmlRootAttributes = list.ToArray(list.Count);
+            XmlRootAttributes = list.ToArray();
         }
         }
     }
     }
 }
 }

+ 1 - 1
Emby.Dlna/Service/BaseControlHandler.cs

@@ -242,7 +242,7 @@ namespace Emby.Dlna.Service
             }
             }
 
 
             var originalHeaders = request.Headers;
             var originalHeaders = request.Headers;
-            var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray(originalHeaders.Count));
+            var headers = string.Join(", ", originalHeaders.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
 
 
             Logger.Debug("Control request. Headers: {0}", headers);
             Logger.Debug("Control request. Headers: {0}", headers);
         }
         }

+ 2 - 2
Emby.Drawing/ImageProcessor.cs

@@ -564,7 +564,7 @@ namespace Emby.Drawing
             var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList();
             var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList();
             cacheKeys.Add(originalImagePath + dateModified.Ticks);
             cacheKeys.Add(originalImagePath + dateModified.Ticks);
 
 
-            return string.Join("|", cacheKeys.ToArray(cacheKeys.Count)).GetMD5().ToString("N");
+            return string.Join("|", cacheKeys.ToArray()).GetMD5().ToString("N");
         }
         }
 
 
         private async Task<ValueTuple<string, DateTime>> GetSupportedImage(string originalImagePath, DateTime dateModified)
         private async Task<ValueTuple<string, DateTime>> GetSupportedImage(string originalImagePath, DateTime dateModified)
@@ -919,4 +919,4 @@ namespace Emby.Drawing
             }
             }
         }
         }
     }
     }
-}
+}

+ 1 - 1
Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs

@@ -466,7 +466,7 @@ namespace Emby.Server.Implementations.Activity
                 {
                 {
                     Name = string.Format(_localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
                     Name = string.Format(_localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
                     Type = NotificationType.TaskFailed.ToString(),
                     Type = NotificationType.TaskFailed.ToString(),
-                    Overview = string.Join(Environment.NewLine, vals.ToArray(vals.Count)),
+                    Overview = string.Join(Environment.NewLine, vals.ToArray()),
                     ShortOverview = runningTime,
                     ShortOverview = runningTime,
                     Severity = LogSeverity.Error
                     Severity = LogSeverity.Error
                 });
                 });

+ 4 - 4
Emby.Server.Implementations/Activity/ActivityRepository.cs

@@ -189,13 +189,13 @@ namespace Emby.Server.Implementations.Activity
 
 
                     var whereTextWithoutPaging = whereClauses.Count == 0 ?
                     var whereTextWithoutPaging = whereClauses.Count == 0 ?
                       string.Empty :
                       string.Empty :
-                      " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
+                      " where " + string.Join(" AND ", whereClauses.ToArray());
 
 
                     if (startIndex.HasValue && startIndex.Value > 0)
                     if (startIndex.HasValue && startIndex.Value > 0)
                     {
                     {
                         var pagingWhereText = whereClauses.Count == 0 ?
                         var pagingWhereText = whereClauses.Count == 0 ?
                             string.Empty :
                             string.Empty :
-                            " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
+                            " where " + string.Join(" AND ", whereClauses.ToArray());
 
 
                         whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM ActivityLog {0} ORDER BY DateCreated DESC LIMIT {1})",
                         whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM ActivityLog {0} ORDER BY DateCreated DESC LIMIT {1})",
                             pagingWhereText,
                             pagingWhereText,
@@ -204,7 +204,7 @@ namespace Emby.Server.Implementations.Activity
 
 
                     var whereText = whereClauses.Count == 0 ?
                     var whereText = whereClauses.Count == 0 ?
                         string.Empty :
                         string.Empty :
-                        " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
+                        " where " + string.Join(" AND ", whereClauses.ToArray());
 
 
                     commandText += whereText;
                     commandText += whereText;
 
 
@@ -249,7 +249,7 @@ namespace Emby.Server.Implementations.Activity
                             result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First();
                             result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First();
                         }
                         }
 
 
-                        result.Items = list.ToArray(list.Count);
+                        result.Items = list.ToArray();
                         return result;
                         return result;
 
 
                     }, ReadTransactionMode);
                     }, ReadTransactionMode);

+ 31 - 6
Emby.Server.Implementations/ApplicationHost.cs

@@ -728,7 +728,7 @@ namespace Emby.Server.Implementations
 
 
             Logger.Info("ServerId: {0}", SystemId);
             Logger.Info("ServerId: {0}", SystemId);
 
 
-            var entryPoints = GetExports<IServerEntryPoint>().ToList();
+            var entryPoints = GetExports<IServerEntryPoint>();
             RunEntryPoints(entryPoints, true);
             RunEntryPoints(entryPoints, true);
 
 
             Logger.Info("Core startup complete");
             Logger.Info("Core startup complete");
@@ -1962,6 +1962,7 @@ namespace Emby.Server.Implementations
         public async Task<SystemInfo> GetSystemInfo(CancellationToken cancellationToken)
         public async Task<SystemInfo> GetSystemInfo(CancellationToken cancellationToken)
         {
         {
             var localAddress = await GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
             var localAddress = await GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
+            var wanAddress = await GetWanApiUrl(cancellationToken).ConfigureAwait(false);
 
 
             return new SystemInfo
             return new SystemInfo
             {
             {
@@ -1984,8 +1985,7 @@ namespace Emby.Server.Implementations
                 CanSelfRestart = CanSelfRestart,
                 CanSelfRestart = CanSelfRestart,
                 CanSelfUpdate = CanSelfUpdate,
                 CanSelfUpdate = CanSelfUpdate,
                 CanLaunchWebBrowser = CanLaunchWebBrowser,
                 CanLaunchWebBrowser = CanLaunchWebBrowser,
-                // TODO - remove WanAddress
-                WanAddress = "0.0.0.0",
+                WanAddress = wanAddress,
                 HasUpdateAvailable = HasUpdateAvailable,
                 HasUpdateAvailable = HasUpdateAvailable,
                 SupportsAutoRunAtStartup = SupportsAutoRunAtStartup,
                 SupportsAutoRunAtStartup = SupportsAutoRunAtStartup,
                 TranscodingTempPath = ApplicationPaths.TranscodingTempPath,
                 TranscodingTempPath = ApplicationPaths.TranscodingTempPath,
@@ -2012,14 +2012,13 @@ namespace Emby.Server.Implementations
         public async Task<PublicSystemInfo> GetPublicSystemInfo(CancellationToken cancellationToken)
         public async Task<PublicSystemInfo> GetPublicSystemInfo(CancellationToken cancellationToken)
         {
         {
             var localAddress = await GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
             var localAddress = await GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
-
+            var wanAddress = await GetWanApiUrl(cancellationToken).ConfigureAwait(false);
             return new PublicSystemInfo
             return new PublicSystemInfo
             {
             {
                 Version = ApplicationVersion.ToString(),
                 Version = ApplicationVersion.ToString(),
                 Id = SystemId,
                 Id = SystemId,
                 OperatingSystem = EnvironmentInfo.OperatingSystem.ToString(),
                 OperatingSystem = EnvironmentInfo.OperatingSystem.ToString(),
-                // TODO - remove WanAddress
-                WanAddress = "0.0.0.0",
+                WanAddress = wanAddress,
                 ServerName = FriendlyName,
                 ServerName = FriendlyName,
                 LocalAddress = localAddress
                 LocalAddress = localAddress
             };
             };
@@ -2060,6 +2059,32 @@ namespace Emby.Server.Implementations
             return null;
             return null;
         }
         }
 
 
+        public async Task<string> GetWanApiUrl(CancellationToken cancellationToken)
+        {
+            var url = "http://ipv4.icanhazip.com";
+            try
+            {
+                using (var response = await HttpClient.Get(new HttpRequestOptions
+                {
+                    Url = url,
+                    LogErrorResponseBody = false,
+                    LogErrors = false,
+                    LogRequest = false,
+                    TimeoutMs = 10000,
+                    BufferContent = false,
+                    CancellationToken = cancellationToken
+                }))
+                {
+                    return GetLocalApiUrl(response.ReadToEnd().Trim());
+                }
+            }
+            catch(Exception ex)
+            {
+                Logger.ErrorException("Error getting WAN Ip address information", ex);
+            }
+            return null;
+        }
+
         public string GetLocalApiUrl(IpAddressInfo ipAddress)
         public string GetLocalApiUrl(IpAddressInfo ipAddress)
         {
         {
             if (ipAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
             if (ipAddress.AddressFamily == IpAddressFamily.InterNetworkV6)

+ 4 - 4
Emby.Server.Implementations/Channels/ChannelManager.cs

@@ -239,7 +239,7 @@ namespace Emby.Server.Implementations.Channels
                 all = all.Take(query.Limit.Value).ToList();
                 all = all.Take(query.Limit.Value).ToList();
             }
             }
 
 
-            var returnItems = all.ToArray(all.Count);
+            var returnItems = all.ToArray();
 
 
             if (query.RefreshLatestChannelItems)
             if (query.RefreshLatestChannelItems)
             {
             {
@@ -1011,7 +1011,7 @@ namespace Emby.Server.Implementations.Channels
             {
             {
                 item.Name = info.Name;
                 item.Name = info.Name;
                 item.Genres = info.Genres.ToArray();
                 item.Genres = info.Genres.ToArray();
-                item.Studios = info.Studios.ToArray(info.Studios.Count);
+                item.Studios = info.Studios.ToArray();
                 item.CommunityRating = info.CommunityRating;
                 item.CommunityRating = info.CommunityRating;
                 item.Overview = info.Overview;
                 item.Overview = info.Overview;
                 item.IndexNumber = info.IndexNumber;
                 item.IndexNumber = info.IndexNumber;
@@ -1021,7 +1021,7 @@ namespace Emby.Server.Implementations.Channels
                 item.ProviderIds = info.ProviderIds;
                 item.ProviderIds = info.ProviderIds;
                 item.OfficialRating = info.OfficialRating;
                 item.OfficialRating = info.OfficialRating;
                 item.DateCreated = info.DateCreated ?? DateTime.UtcNow;
                 item.DateCreated = info.DateCreated ?? DateTime.UtcNow;
-                item.Tags = info.Tags.ToArray(info.Tags.Count);
+                item.Tags = info.Tags.ToArray();
                 item.OriginalTitle = info.OriginalTitle;
                 item.OriginalTitle = info.OriginalTitle;
             }
             }
             else if (info.Type == ChannelItemType.Folder && info.FolderType == ChannelFolderType.Container)
             else if (info.Type == ChannelItemType.Folder && info.FolderType == ChannelFolderType.Container)
@@ -1043,7 +1043,7 @@ namespace Emby.Server.Implementations.Channels
             var hasAlbumArtists = item as IHasAlbumArtist;
             var hasAlbumArtists = item as IHasAlbumArtist;
             if (hasAlbumArtists != null)
             if (hasAlbumArtists != null)
             {
             {
-                hasAlbumArtists.AlbumArtists = info.AlbumArtists.ToArray(info.AlbumArtists.Count);
+                hasAlbumArtists.AlbumArtists = info.AlbumArtists.ToArray();
             }
             }
 
 
             var trailer = item as Trailer;
             var trailer = item as Trailer;

+ 1 - 1
Emby.Server.Implementations/Collections/CollectionManager.cs

@@ -219,7 +219,7 @@ namespace Emby.Server.Implementations.Collections
             {
             {
                 var newList = collection.LinkedChildren.ToList();
                 var newList = collection.LinkedChildren.ToList();
                 newList.AddRange(list);
                 newList.AddRange(list);
-                collection.LinkedChildren = newList.ToArray(newList.Count);
+                collection.LinkedChildren = newList.ToArray();
 
 
                 collection.UpdateRatingToItems(linkedChildrenList);
                 collection.UpdateRatingToItems(linkedChildrenList);
 
 

+ 16 - 16
Emby.Server.Implementations/Data/SqliteItemRepository.cs

@@ -1148,7 +1148,7 @@ namespace Emby.Server.Implementations.Data
                 }
                 }
             }
             }
 
 
-            item.ImageInfos = list.ToArray(list.Count);
+            item.ImageInfos = list.ToArray();
         }
         }
 
 
         public string ToValueString(ItemImageInfo image)
         public string ToValueString(ItemImageInfo image)
@@ -2566,7 +2566,7 @@ namespace Emby.Server.Implementations.Data
                 excludeIds.Add(item.Id);
                 excludeIds.Add(item.Id);
                 excludeIds.AddRange(item.ExtraIds);
                 excludeIds.AddRange(item.ExtraIds);
 
 
-                query.ExcludeItemIds = excludeIds.ToArray(excludeIds.Count);
+                query.ExcludeItemIds = excludeIds.ToArray();
                 query.ExcludeProviderIds = item.ProviderIds;
                 query.ExcludeProviderIds = item.ProviderIds;
             }
             }
 
 
@@ -2587,7 +2587,7 @@ namespace Emby.Server.Implementations.Data
                 list.Add(builder.ToString());
                 list.Add(builder.ToString());
             }
             }
 
 
-            return list.ToArray(list.Count);
+            return list.ToArray();
         }
         }
 
 
         private void BindSearchParams(InternalItemsQuery query, IStatement statement)
         private void BindSearchParams(InternalItemsQuery query, IStatement statement)
@@ -2666,7 +2666,7 @@ namespace Emby.Server.Implementations.Data
 
 
             if (groups.Count > 0)
             if (groups.Count > 0)
             {
             {
-                return " Group by " + string.Join(",", groups.ToArray(groups.Count));
+                return " Group by " + string.Join(",", groups.ToArray());
             }
             }
 
 
             return string.Empty;
             return string.Empty;
@@ -2703,7 +2703,7 @@ namespace Emby.Server.Implementations.Data
 
 
             var whereText = whereClauses.Count == 0 ?
             var whereText = whereClauses.Count == 0 ?
                 string.Empty :
                 string.Empty :
-                " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
+                " where " + string.Join(" AND ", whereClauses.ToArray());
 
 
             commandText += whereText;
             commandText += whereText;
 
 
@@ -2761,7 +2761,7 @@ namespace Emby.Server.Implementations.Data
 
 
             var whereText = whereClauses.Count == 0 ?
             var whereText = whereClauses.Count == 0 ?
                 string.Empty :
                 string.Empty :
-                " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
+                " where " + string.Join(" AND ", whereClauses.ToArray());
 
 
             commandText += whereText;
             commandText += whereText;
 
 
@@ -2938,7 +2938,7 @@ namespace Emby.Server.Implementations.Data
                 var returnList = GetItemList(query);
                 var returnList = GetItemList(query);
                 return new QueryResult<BaseItem>
                 return new QueryResult<BaseItem>
                 {
                 {
-                    Items = returnList.ToArray(returnList.Count),
+                    Items = returnList.ToArray(),
                     TotalRecordCount = returnList.Count
                     TotalRecordCount = returnList.Count
                 };
                 };
             }
             }
@@ -2961,7 +2961,7 @@ namespace Emby.Server.Implementations.Data
 
 
             var whereText = whereClauses.Count == 0 ?
             var whereText = whereClauses.Count == 0 ?
                 string.Empty :
                 string.Empty :
-                " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
+                " where " + string.Join(" AND ", whereClauses.ToArray());
 
 
             var whereTextWithoutPaging = whereText;
             var whereTextWithoutPaging = whereText;
 
 
@@ -3079,7 +3079,7 @@ namespace Emby.Server.Implementations.Data
 
 
                         LogQueryTime("GetItems", commandText, now);
                         LogQueryTime("GetItems", commandText, now);
 
 
-                        result.Items = list.ToArray(list.Count);
+                        result.Items = list.ToArray();
                         return result;
                         return result;
 
 
                     }, ReadTransactionMode);
                     }, ReadTransactionMode);
@@ -3227,7 +3227,7 @@ namespace Emby.Server.Implementations.Data
 
 
             var whereText = whereClauses.Count == 0 ?
             var whereText = whereClauses.Count == 0 ?
                 string.Empty :
                 string.Empty :
-                " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
+                " where " + string.Join(" AND ", whereClauses.ToArray());
 
 
             commandText += whereText;
             commandText += whereText;
 
 
@@ -3299,7 +3299,7 @@ namespace Emby.Server.Implementations.Data
 
 
             var whereText = whereClauses.Count == 0 ?
             var whereText = whereClauses.Count == 0 ?
                 string.Empty :
                 string.Empty :
-                " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
+                " where " + string.Join(" AND ", whereClauses.ToArray());
 
 
             commandText += whereText;
             commandText += whereText;
 
 
@@ -3372,7 +3372,7 @@ namespace Emby.Server.Implementations.Data
                 var returnList = GetItemIdsList(query);
                 var returnList = GetItemIdsList(query);
                 return new QueryResult<Guid>
                 return new QueryResult<Guid>
                 {
                 {
-                    Items = returnList.ToArray(returnList.Count),
+                    Items = returnList.ToArray(),
                     TotalRecordCount = returnList.Count
                     TotalRecordCount = returnList.Count
                 };
                 };
             }
             }
@@ -3387,7 +3387,7 @@ namespace Emby.Server.Implementations.Data
 
 
             var whereText = whereClauses.Count == 0 ?
             var whereText = whereClauses.Count == 0 ?
                 string.Empty :
                 string.Empty :
-                " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
+                " where " + string.Join(" AND ", whereClauses.ToArray());
 
 
             var whereTextWithoutPaging = whereText;
             var whereTextWithoutPaging = whereText;
 
 
@@ -3495,7 +3495,7 @@ namespace Emby.Server.Implementations.Data
 
 
                         LogQueryTime("GetItemIds", commandText, now);
                         LogQueryTime("GetItemIds", commandText, now);
 
 
-                        result.Items = list.ToArray(list.Count);
+                        result.Items = list.ToArray();
                         return result;
                         return result;
 
 
                     }, ReadTransactionMode);
                     }, ReadTransactionMode);
@@ -3690,7 +3690,7 @@ namespace Emby.Server.Implementations.Data
                     statement.TryBind("@IsMovie", true);
                     statement.TryBind("@IsMovie", true);
                 }
                 }
 
 
-                whereClauses.Add("(" + string.Join(" OR ", programAttribtues.ToArray(programAttribtues.Count)) + ")");
+                whereClauses.Add("(" + string.Join(" OR ", programAttribtues.ToArray()) + ")");
             }
             }
             else if (query.IsMovie.HasValue)
             else if (query.IsMovie.HasValue)
             {
             {
@@ -5813,7 +5813,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
                         {
                         {
                             result.TotalRecordCount = list.Count;
                             result.TotalRecordCount = list.Count;
                         }
                         }
-                        result.Items = list.ToArray(list.Count);
+                        result.Items = list.ToArray();
 
 
                         return result;
                         return result;
 
 

+ 2 - 2
Emby.Server.Implementations/Devices/DeviceManager.cs

@@ -289,7 +289,7 @@ namespace Emby.Server.Implementations.Devices
 
 
                 var list = history.FilesUploaded.ToList();
                 var list = history.FilesUploaded.ToList();
                 list.Add(file);
                 list.Add(file);
-                history.FilesUploaded = list.ToArray(list.Count);
+                history.FilesUploaded = list.ToArray();
 
 
                 _json.SerializeToFile(history, path);
                 _json.SerializeToFile(history, path);
             }
             }
@@ -501,4 +501,4 @@ namespace Emby.Server.Implementations.Devices
             return config.GetConfiguration<DevicesOptions>("devices");
             return config.GetConfiguration<DevicesOptions>("devices");
         }
         }
     }
     }
-}
+}

+ 1 - 1
Emby.Server.Implementations/Dto/DtoService.cs

@@ -648,7 +648,7 @@ namespace Emby.Server.Implementations.Dto
                 }
                 }
             }
             }
 
 
-            dto.People = list.ToArray(list.Count);
+            dto.People = list.ToArray();
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 2 - 3
Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs

@@ -12,7 +12,6 @@ using MediaBrowser.Model.Events;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Threading;
 using MediaBrowser.Model.Threading;
 using Mono.Nat;
 using Mono.Nat;
-using MediaBrowser.Model.Extensions;
 using System.Threading;
 using System.Threading;
 
 
 namespace Emby.Server.Implementations.EntryPoints
 namespace Emby.Server.Implementations.EntryPoints
@@ -59,7 +58,7 @@ namespace Emby.Server.Implementations.EntryPoints
             values.Add(_appHost.EnableHttps.ToString());
             values.Add(_appHost.EnableHttps.ToString());
             values.Add((config.EnableRemoteAccess).ToString());
             values.Add((config.EnableRemoteAccess).ToString());
 
 
-            return string.Join("|", values.ToArray(values.Count));
+            return string.Join("|", values.ToArray());
         }
         }
 
 
         void _config_ConfigurationUpdated(object sender, EventArgs e)
         void _config_ConfigurationUpdated(object sender, EventArgs e)
@@ -316,4 +315,4 @@ namespace Emby.Server.Implementations.EntryPoints
             }
             }
         }
         }
     }
     }
-}
+}

+ 1 - 1
Emby.Server.Implementations/EntryPoints/UsageEntryPoint.cs

@@ -58,7 +58,7 @@ namespace Emby.Server.Implementations.EntryPoints
                     session.ApplicationVersion
                     session.ApplicationVersion
                 };
                 };
 
 
-                var key = string.Join("_", keys.ToArray(keys.Count)).GetMD5();
+                var key = string.Join("_", keys.ToArray()).GetMD5();
 
 
                 ClientInfo info;
                 ClientInfo info;
                 if (!_apps.TryGetValue(key, out info))
                 if (!_apps.TryGetValue(key, out info))

+ 2 - 2
Emby.Server.Implementations/HttpServer/HttpListenerHost.cs

@@ -825,7 +825,7 @@ namespace Emby.Server.Implementations.HttpServer
                 });
                 });
             }
             }
 
 
-            return routes.ToArray(routes.Count);
+            return routes.ToArray();
         }
         }
 
 
         public Func<string, object> GetParseFn(Type propertyType)
         public Func<string, object> GetParseFn(Type propertyType)
@@ -954,4 +954,4 @@ namespace Emby.Server.Implementations.HttpServer
             _listener.Start(UrlPrefixes);
             _listener.Start(UrlPrefixes);
         }
         }
     }
     }
-}
+}

+ 8 - 5
Emby.Server.Implementations/HttpServer/HttpResultFactory.cs

@@ -112,12 +112,15 @@ namespace Emby.Server.Implementations.HttpServer
         /// </summary>
         /// </summary>
         private IHasHeaders GetHttpResult(IRequest requestContext, byte[] content, string contentType, bool addCachePrevention, IDictionary<string, string> responseHeaders = null)
         private IHasHeaders GetHttpResult(IRequest requestContext, byte[] content, string contentType, bool addCachePrevention, IDictionary<string, string> responseHeaders = null)
         {
         {
-            IHasHeaders result;
-
-            var compressionType = requestContext == null ? null : GetCompressionType(requestContext, content, contentType);
+            string compressionType = null;
+            bool isHeadRequest = false;
 
 
-            var isHeadRequest = string.Equals(requestContext.Verb, "head", StringComparison.OrdinalIgnoreCase);
+            if (requestContext != null) {
+                compressionType = GetCompressionType(requestContext, content, contentType);
+                isHeadRequest = string.Equals(requestContext.Verb, "head", StringComparison.OrdinalIgnoreCase);
+            }
 
 
+            IHasHeaders result;
             if (string.IsNullOrEmpty(compressionType))
             if (string.IsNullOrEmpty(compressionType))
             {
             {
                 var contentLength = content.Length;
                 var contentLength = content.Length;
@@ -791,4 +794,4 @@ namespace Emby.Server.Implementations.HttpServer
     {
     {
         byte[] Compress(byte[] content);
         byte[] Compress(byte[] content);
     }
     }
-}
+}

+ 1 - 0
Emby.Server.Implementations/IO/SharpCifs/Util/Sharpen/Collections.cs

@@ -2,6 +2,7 @@ using System.Collections;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Collections.ObjectModel;
 
 
+// TODO: @bond Remove
 namespace SharpCifs.Util.Sharpen
 namespace SharpCifs.Util.Sharpen
 {
 {
     internal static class Collections<T>
     internal static class Collections<T>

+ 3 - 3
Emby.Server.Implementations/Library/LibraryManager.cs

@@ -730,7 +730,7 @@ namespace Emby.Server.Implementations.Library
 
 
             _fileSystem.CreateDirectory(rootFolderPath);
             _fileSystem.CreateDirectory(rootFolderPath);
 
 
-            var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath));
+            var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath))).DeepCopy<Folder,AggregateFolder>();
 
 
             // In case program data folder was moved
             // In case program data folder was moved
             if (!string.Equals(rootFolder.Path, rootFolderPath, StringComparison.Ordinal))
             if (!string.Equals(rootFolder.Path, rootFolderPath, StringComparison.Ordinal))
@@ -799,7 +799,7 @@ namespace Emby.Server.Implementations.Library
 
 
                         if (tmpItem == null)
                         if (tmpItem == null)
                         {
                         {
-                            tmpItem = (UserRootFolder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath));
+                            tmpItem = ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath))).DeepCopy<Folder,UserRootFolder>();
                         }
                         }
 
 
                         // In case program data folder was moved
                         // In case program data folder was moved
@@ -1493,7 +1493,7 @@ namespace Emby.Server.Implementations.Library
 
 
             return new QueryResult<BaseItem>
             return new QueryResult<BaseItem>
             {
             {
-                Items = list.ToArray(list.Count)
+                Items = list.ToArray()
             };
             };
         }
         }
 
 

+ 2 - 2
Emby.Server.Implementations/Library/SearchEngine.cs

@@ -161,8 +161,8 @@ namespace Emby.Server.Implementations.Library
             var searchQuery = new InternalItemsQuery(user)
             var searchQuery = new InternalItemsQuery(user)
             {
             {
                 SearchTerm = searchTerm,
                 SearchTerm = searchTerm,
-                ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count),
-                IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count),
+                ExcludeItemTypes = excludeItemTypes.ToArray(),
+                IncludeItemTypes = includeItemTypes.ToArray(),
                 Limit = query.Limit,
                 Limit = query.Limit,
                 IncludeItemsByName = string.IsNullOrEmpty(query.ParentId),
                 IncludeItemsByName = string.IsNullOrEmpty(query.ParentId),
                 ParentId = string.IsNullOrEmpty(query.ParentId) ? Guid.Empty : new Guid(query.ParentId),
                 ParentId = string.IsNullOrEmpty(query.ParentId) ? Guid.Empty : new Guid(query.ParentId),

+ 1 - 1
Emby.Server.Implementations/Library/UserViewManager.cs

@@ -354,7 +354,7 @@ namespace Emby.Server.Implementations.Library
                 Limit = limit * 5,
                 Limit = limit * 5,
                 IsPlayed = isPlayed,
                 IsPlayed = isPlayed,
                 DtoOptions = options,
                 DtoOptions = options,
-                MediaTypes = mediaTypes.ToArray(mediaTypes.Count)
+                MediaTypes = mediaTypes.ToArray()
             };
             };
 
 
             if (parents.Count == 0)
             if (parents.Count == 0)

+ 1 - 1
Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs

@@ -139,7 +139,7 @@ namespace Emby.Server.Implementations.LiveTv
                 dto.ProgramId = GetInternalProgramId(info.ProgramId).ToString("N");
                 dto.ProgramId = GetInternalProgramId(info.ProgramId).ToString("N");
             }
             }
 
 
-            dto.DayPattern = info.Days == null ? null : GetDayPattern(info.Days.ToArray(info.Days.Count));
+            dto.DayPattern = info.Days == null ? null : GetDayPattern(info.Days.ToArray());
 
 
             FillImages(dto, info.Name, info.SeriesId);
             FillImages(dto, info.Name, info.SeriesId);
 
 

+ 11 - 11
Emby.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -1140,7 +1140,7 @@ namespace Emby.Server.Implementations.LiveTv
             var dtoOptions = new DtoOptions();
             var dtoOptions = new DtoOptions();
             var fields = dtoOptions.Fields.ToList();
             var fields = dtoOptions.Fields.ToList();
             fields.Remove(ItemFields.BasicSyncInfo);
             fields.Remove(ItemFields.BasicSyncInfo);
-            dtoOptions.Fields = fields.ToArray(fields.Count);
+            dtoOptions.Fields = fields.ToArray();
 
 
             progress.Report(100);
             progress.Report(100);
         }
         }
@@ -1458,16 +1458,16 @@ namespace Emby.Server.Implementations.LiveTv
             {
             {
                 MediaTypes = new[] { MediaType.Video },
                 MediaTypes = new[] { MediaType.Video },
                 Recursive = true,
                 Recursive = true,
-                AncestorIds = folderIds.ToArray(folderIds.Count),
+                AncestorIds = folderIds.ToArray(),
                 IsFolder = false,
                 IsFolder = false,
                 IsVirtualItem = false,
                 IsVirtualItem = false,
                 Limit = limit,
                 Limit = limit,
                 StartIndex = query.StartIndex,
                 StartIndex = query.StartIndex,
                 OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending) },
                 OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending) },
                 EnableTotalRecordCount = query.EnableTotalRecordCount,
                 EnableTotalRecordCount = query.EnableTotalRecordCount,
-                IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count),
-                ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count),
-                Genres = genres.ToArray(genres.Count),
+                IncludeItemTypes = includeItemTypes.ToArray(),
+                ExcludeItemTypes = excludeItemTypes.ToArray(),
+                Genres = genres.ToArray(),
                 DtoOptions = dtoOptions
                 DtoOptions = dtoOptions
             });
             });
 
 
@@ -1791,7 +1791,7 @@ namespace Emby.Server.Implementations.LiveTv
 
 
             var returnArray = returnList
             var returnArray = returnList
                 .OrderBy(i => i.StartDate)
                 .OrderBy(i => i.StartDate)
-                .ToArray(returnList.Count);
+                .ToArray();
 
 
             return new QueryResult<TimerInfoDto>
             return new QueryResult<TimerInfoDto>
             {
             {
@@ -2338,7 +2338,7 @@ namespace Emby.Server.Implementations.LiveTv
             fields.Remove(ItemFields.CanDownload);
             fields.Remove(ItemFields.CanDownload);
             fields.Remove(ItemFields.DisplayPreferencesId);
             fields.Remove(ItemFields.DisplayPreferencesId);
             fields.Remove(ItemFields.Etag);
             fields.Remove(ItemFields.Etag);
-            options.Fields = fields.ToArray(fields.Count);
+            options.Fields = fields.ToArray();
         }
         }
 
 
         public Folder GetInternalLiveTvFolder(CancellationToken cancellationToken)
         public Folder GetInternalLiveTvFolder(CancellationToken cancellationToken)
@@ -2373,7 +2373,7 @@ namespace Emby.Server.Implementations.LiveTv
             {
             {
                 info.Id = Guid.NewGuid().ToString("N");
                 info.Id = Guid.NewGuid().ToString("N");
                 list.Add(info);
                 list.Add(info);
-                config.TunerHosts = list.ToArray(list.Count);
+                config.TunerHosts = list.ToArray();
             }
             }
             else
             else
             {
             {
@@ -2412,7 +2412,7 @@ namespace Emby.Server.Implementations.LiveTv
             {
             {
                 info.Id = Guid.NewGuid().ToString("N");
                 info.Id = Guid.NewGuid().ToString("N");
                 list.Add(info);
                 list.Add(info);
-                config.ListingProviders = list.ToArray(list.Count);
+                config.ListingProviders = list.ToArray();
             }
             }
             else
             else
             {
             {
@@ -2451,7 +2451,7 @@ namespace Emby.Server.Implementations.LiveTv
                     Name = tunerChannelId,
                     Name = tunerChannelId,
                     Value = providerChannelId
                     Value = providerChannelId
                 });
                 });
-                listingsProviderInfo.ChannelMappings = list.ToArray(list.Count);
+                listingsProviderInfo.ChannelMappings = list.ToArray();
             }
             }
 
 
             _config.SaveConfiguration("livetv", config);
             _config.SaveConfiguration("livetv", config);
@@ -2602,4 +2602,4 @@ namespace Emby.Server.Implementations.LiveTv
             return folders.Cast<BaseItem>().ToList();
             return folders.Cast<BaseItem>().ToList();
         }
         }
     }
     }
-}
+}

+ 1 - 1
Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs

@@ -106,7 +106,7 @@ namespace Emby.Server.Implementations.LiveTv
                     openKeys.Add(item.GetType().Name);
                     openKeys.Add(item.GetType().Name);
                     openKeys.Add(item.Id.ToString("N"));
                     openKeys.Add(item.Id.ToString("N"));
                     openKeys.Add(source.Id ?? string.Empty);
                     openKeys.Add(source.Id ?? string.Empty);
-                    source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray(openKeys.Count));
+                    source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray());
                 }
                 }
 
 
                 // Dummy this up so that direct play checks can still run
                 // Dummy this up so that direct play checks can still run

+ 1 - 1
Emby.Server.Implementations/Networking/NetworkManager.cs

@@ -706,7 +706,7 @@ namespace Emby.Server.Implementations.Networking
         public async Task<IpAddressInfo[]> GetHostAddressesAsync(string host)
         public async Task<IpAddressInfo[]> GetHostAddressesAsync(string host)
         {
         {
             var addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false);
             var addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false);
-            return addresses.Select(ToIpAddressInfo).ToArray(addresses.Length);
+            return addresses.Select(ToIpAddressInfo).ToArray();
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 2 - 2
Emby.Server.Implementations/Playlists/PlaylistManager.cs

@@ -208,7 +208,7 @@ namespace Emby.Server.Implementations.Playlists
 
 
             var newList = playlist.LinkedChildren.ToList();
             var newList = playlist.LinkedChildren.ToList();
             newList.AddRange(list);
             newList.AddRange(list);
-            playlist.LinkedChildren = newList.ToArray(newList.Count);
+            playlist.LinkedChildren = newList.ToArray();
 
 
             playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
             playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
 
 
@@ -290,7 +290,7 @@ namespace Emby.Server.Implementations.Playlists
                 newList.Insert(newIndex, item);
                 newList.Insert(newIndex, item);
             }
             }
 
 
-            playlist.LinkedChildren = newList.ToArray(newList.Count);
+            playlist.LinkedChildren = newList.ToArray();
 
 
             playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
             playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
 
 

+ 1 - 1
Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs

@@ -145,7 +145,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
 
 
                         _fileSystem.CreateDirectory(parentPath);
                         _fileSystem.CreateDirectory(parentPath);
 
 
-                        _fileSystem.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray(previouslyFailedImages.Count)));
+                        _fileSystem.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray()));
                     }
                     }
 
 
                     numComplete++;
                     numComplete++;

+ 0 - 142
Emby.Server.Implementations/ScheduledTasks/PluginUpdateTask.cs

@@ -1,142 +0,0 @@
-using MediaBrowser.Common;
-using MediaBrowser.Common.Updates;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Progress;
-using MediaBrowser.Model.Tasks;
-
-namespace Emby.Server.Implementations.ScheduledTasks
-{
-    /// <summary>
-    /// Plugin Update Task
-    /// </summary>
-    public class PluginUpdateTask : IScheduledTask, IConfigurableScheduledTask
-    {
-        /// <summary>
-        /// The _logger
-        /// </summary>
-        private readonly ILogger _logger;
-
-        private readonly IInstallationManager _installationManager;
-
-        private readonly IApplicationHost _appHost;
-
-        public PluginUpdateTask(ILogger logger, IInstallationManager installationManager, IApplicationHost appHost)
-        {
-            _logger = logger;
-            _installationManager = installationManager;
-            _appHost = appHost;
-        }
-
-        /// <summary>
-        /// Creates the triggers that define when the task will run
-        /// </summary>
-        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
-        public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
-        {
-            return new[] { 
-            
-                // At startup
-                new TaskTriggerInfo {Type = TaskTriggerInfo.TriggerStartup},
-
-                // Every so often
-                new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
-            };
-        }
-
-        public string Key
-        {
-            get { return "PluginUpdates"; }
-        }
-
-        /// <summary>
-        /// Update installed plugins
-        /// </summary>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <param name="progress">The progress.</param>
-        /// <returns>Task.</returns>
-        public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
-        {
-            progress.Report(0);
-
-            var packagesToInstall = (await _installationManager.GetAvailablePluginUpdates(_appHost.ApplicationVersion, true, cancellationToken).ConfigureAwait(false)).ToList();
-
-            progress.Report(10);
-
-            var numComplete = 0;
-
-            foreach (var package in packagesToInstall)
-            {
-                cancellationToken.ThrowIfCancellationRequested();
-
-                try
-                {
-                    await _installationManager.InstallPackage(package, true, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false);
-                }
-                catch (OperationCanceledException)
-                {
-                    // InstallPackage has it's own inner cancellation token, so only throw this if it's ours
-                    if (cancellationToken.IsCancellationRequested)
-                    {
-                        throw;
-                    }
-                }
-                catch (HttpException ex)
-                {
-                    _logger.ErrorException("Error downloading {0}", ex, package.name);
-                }
-                catch (IOException ex)
-                {
-                    _logger.ErrorException("Error updating {0}", ex, package.name);
-                }
-
-                // Update progress
-                lock (progress)
-                {
-                    numComplete++;
-                    double percent = numComplete;
-                    percent /= packagesToInstall.Count;
-
-                    progress.Report(90 * percent + 10);
-                }
-            }
-
-            progress.Report(100);
-        }
-
-        /// <summary>
-        /// Gets the name of the task
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name
-        {
-            get { return "Check for plugin updates"; }
-        }
-
-        /// <summary>
-        /// Gets the description.
-        /// </summary>
-        /// <value>The description.</value>
-        public string Description
-        {
-            get { return "Downloads and installs updates for plugins that are configured to update automatically."; }
-        }
-
-        public string Category
-        {
-            get { return "Application"; }
-        }
-
-        public bool IsHidden => true;
-
-        public bool IsEnabled => true;
-
-        public bool IsLogged => true;
-    }
-}

+ 2 - 3
Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs

@@ -9,7 +9,6 @@ using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Progress;
 using MediaBrowser.Common.Progress;
 using MediaBrowser.Model.Events;
 using MediaBrowser.Model.Events;
-using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
@@ -276,7 +275,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
             get
             get
             {
             {
                 var triggers = InternalTriggers;
                 var triggers = InternalTriggers;
-                return triggers.Select(i => i.Item1).ToArray(triggers.Length);
+                return triggers.Select(i => i.Item1).ToArray();
             }
             }
             set
             set
             {
             {
@@ -290,7 +289,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
 
 
                 SaveTriggers(triggerList);
                 SaveTriggers(triggerList);
 
 
-                InternalTriggers = triggerList.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray(triggerList.Length);
+                InternalTriggers = triggerList.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray();
             }
             }
         }
         }
 
 

+ 2 - 2
Emby.Server.Implementations/Security/AuthenticationRepository.cs

@@ -241,7 +241,7 @@ namespace Emby.Server.Implementations.Security
 
 
             var whereTextWithoutPaging = whereClauses.Count == 0 ?
             var whereTextWithoutPaging = whereClauses.Count == 0 ?
               string.Empty :
               string.Empty :
-              " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count));
+              " where " + string.Join(" AND ", whereClauses.ToArray());
 
 
             commandText += whereTextWithoutPaging;
             commandText += whereTextWithoutPaging;
 
 
@@ -298,7 +298,7 @@ namespace Emby.Server.Implementations.Security
                             }
                             }
                         }
                         }
 
 
-                        result.Items = list.ToArray(list.Count);
+                        result.Items = list.ToArray();
                         return result;
                         return result;
 
 
                     }, ReadTransactionMode);
                     }, ReadTransactionMode);

+ 2 - 2
Emby.Server.Implementations/Services/ServiceExec.cs

@@ -181,7 +181,7 @@ namespace Emby.Server.Implementations.Services
                 }
                 }
 
 
                 if (reqFilters.Count > 0)
                 if (reqFilters.Count > 0)
-                    actionCtx.RequestFilters = reqFilters.OrderBy(i => i.Priority).ToArray(reqFilters.Count);
+                    actionCtx.RequestFilters = reqFilters.OrderBy(i => i.Priority).ToArray();
 
 
                 actions.Add(actionCtx);
                 actions.Add(actionCtx);
             }
             }
@@ -220,4 +220,4 @@ namespace Emby.Server.Implementations.Services
             }
             }
         }
         }
     }
     }
-}
+}

+ 5 - 5
Emby.Server.Implementations/Services/ServicePath.cs

@@ -132,13 +132,13 @@ namespace Emby.Server.Implementations.Services
                 }
                 }
             }
             }
 
 
-            var components = componentsList.ToArray(componentsList.Count);
+            var components = componentsList.ToArray();
             this.TotalComponentsCount = components.Length;
             this.TotalComponentsCount = components.Length;
 
 
             this.literalsToMatch = new string[this.TotalComponentsCount];
             this.literalsToMatch = new string[this.TotalComponentsCount];
             this.variablesNames = new string[this.TotalComponentsCount];
             this.variablesNames = new string[this.TotalComponentsCount];
             this.isWildcard = new bool[this.TotalComponentsCount];
             this.isWildcard = new bool[this.TotalComponentsCount];
-            this.componentsWithSeparators = hasSeparators.ToArray(hasSeparators.Count);
+            this.componentsWithSeparators = hasSeparators.ToArray();
             this.PathComponentsCount = this.componentsWithSeparators.Length;
             this.PathComponentsCount = this.componentsWithSeparators.Length;
             string firstLiteralMatch = null;
             string firstLiteralMatch = null;
 
 
@@ -297,7 +297,7 @@ namespace Emby.Server.Implementations.Services
                 if (mi != null && mi.IsStatic) continue;
                 if (mi != null && mi.IsStatic) continue;
                 pis.Add(pi);
                 pis.Add(pi);
             }
             }
-            return pis.ToArray(pis.Count);
+            return pis.ToArray();
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -463,7 +463,7 @@ namespace Emby.Server.Implementations.Services
                 }
                 }
             }
             }
 
 
-            withPathInfoParts = totalComponents.ToArray(totalComponents.Count);
+            withPathInfoParts = totalComponents.ToArray();
             return true;
             return true;
         }
         }
 
 
@@ -574,4 +574,4 @@ namespace Emby.Server.Implementations.Services
             }
             }
         }
         }
     }
     }
-}
+}

+ 5 - 5
Emby.Server.Implementations/Session/SessionManager.cs

@@ -1042,7 +1042,7 @@ namespace Emby.Server.Implementations.Session
                 command.PlayCommand = PlayCommand.PlayNow;
                 command.PlayCommand = PlayCommand.PlayNow;
             }
             }
 
 
-            command.ItemIds = items.Select(i => i.Id).ToArray(items.Count);
+            command.ItemIds = items.Select(i => i.Id).ToArray();
 
 
             if (user != null)
             if (user != null)
             {
             {
@@ -1070,7 +1070,7 @@ namespace Emby.Server.Implementations.Session
 
 
                         if (episodes.Count > 0)
                         if (episodes.Count > 0)
                         {
                         {
-                            command.ItemIds = episodes.Select(i => i.Id).ToArray(episodes.Count);
+                            command.ItemIds = episodes.Select(i => i.Id).ToArray();
                         }
                         }
                     }
                     }
                 }
                 }
@@ -1316,7 +1316,7 @@ namespace Emby.Server.Implementations.Session
                     UserName = user.Name
                     UserName = user.Name
                 });
                 });
 
 
-                session.AdditionalUsers = list.ToArray(list.Count);
+                session.AdditionalUsers = list.ToArray();
             }
             }
         }
         }
 
 
@@ -1345,7 +1345,7 @@ namespace Emby.Server.Implementations.Session
                 var list = session.AdditionalUsers.ToList();
                 var list = session.AdditionalUsers.ToList();
                 list.Remove(user);
                 list.Remove(user);
 
 
-                session.AdditionalUsers = list.ToArray(list.Count);
+                session.AdditionalUsers = list.ToArray();
             }
             }
         }
         }
 
 
@@ -1669,7 +1669,7 @@ namespace Emby.Server.Implementations.Session
                 fields.Remove(ItemFields.Tags);
                 fields.Remove(ItemFields.Tags);
                 fields.Remove(ItemFields.ExtraIds);
                 fields.Remove(ItemFields.ExtraIds);
 
 
-                dtoOptions.Fields = fields.ToArray(fields.Count);
+                dtoOptions.Fields = fields.ToArray();
 
 
                 _itemInfoDtoOptions = dtoOptions;
                 _itemInfoDtoOptions = dtoOptions;
             }
             }

+ 2 - 2
MediaBrowser.Api/BaseApiService.cs

@@ -143,7 +143,7 @@ namespace MediaBrowser.Api
                 {
                 {
                     var list = options.Fields.ToList();
                     var list = options.Fields.ToList();
                     list.Add(Model.Querying.ItemFields.RecursiveItemCount);
                     list.Add(Model.Querying.ItemFields.RecursiveItemCount);
-                    options.Fields = list.ToArray(list.Count);
+                    options.Fields = list.ToArray();
                 }
                 }
 
 
                 if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 ||
                 if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 ||
@@ -156,7 +156,7 @@ namespace MediaBrowser.Api
                 {
                 {
                     var list = options.Fields.ToList();
                     var list = options.Fields.ToList();
                     list.Add(Model.Querying.ItemFields.ChildCount);
                     list.Add(Model.Querying.ItemFields.ChildCount);
-                    options.Fields = list.ToArray(list.Count);
+                    options.Fields = list.ToArray();
                 }
                 }
             }
             }
 
 

+ 2 - 2
MediaBrowser.Api/LiveTv/LiveTvService.cs

@@ -974,7 +974,7 @@ namespace MediaBrowser.Api.LiveTv
             fields.Remove(ItemFields.CanDownload);
             fields.Remove(ItemFields.CanDownload);
             fields.Remove(ItemFields.DisplayPreferencesId);
             fields.Remove(ItemFields.DisplayPreferencesId);
             fields.Remove(ItemFields.Etag);
             fields.Remove(ItemFields.Etag);
-            options.Fields = fields.ToArray(fields.Count);
+            options.Fields = fields.ToArray();
         }
         }
 
 
         public object Get(GetChannel request)
         public object Get(GetChannel request)
@@ -1265,4 +1265,4 @@ namespace MediaBrowser.Api.LiveTv
             return _liveTvManager.ResetTuner(request.Id, CancellationToken.None);
             return _liveTvManager.ResetTuner(request.Id, CancellationToken.None);
         }
         }
     }
     }
-}
+}

+ 6 - 6
MediaBrowser.Api/Movies/MoviesService.cs

@@ -123,7 +123,7 @@ namespace MediaBrowser.Api.Movies
             var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
             var itemsResult = _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
                 Limit = request.Limit,
                 Limit = request.Limit,
-                IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
+                IncludeItemTypes = itemTypes.ToArray(),
                 IsMovie = true,
                 IsMovie = true,
                 SimilarTo = item,
                 SimilarTo = item,
                 EnableGroupByMetadataKey = true,
                 EnableGroupByMetadataKey = true,
@@ -177,12 +177,12 @@ namespace MediaBrowser.Api.Movies
 
 
             var likedMovies = _libraryManager.GetItemList(new InternalItemsQuery(user)
             var likedMovies = _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
-                IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
+                IncludeItemTypes = itemTypes.ToArray(),
                 IsMovie = true,
                 IsMovie = true,
                 OrderBy = new[] { ItemSortBy.Random }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(),
                 OrderBy = new[] { ItemSortBy.Random }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(),
                 Limit = 10,
                 Limit = 10,
                 IsFavoriteOrLiked = true,
                 IsFavoriteOrLiked = true,
-                ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id).ToArray(recentlyPlayedMovies.Count),
+                ExcludeItemIds = recentlyPlayedMovies.Select(i => i.Id).ToArray(),
                 EnableGroupByMetadataKey = true,
                 EnableGroupByMetadataKey = true,
                 ParentId = parentIdGuid,
                 ParentId = parentIdGuid,
                 Recursive = true,
                 Recursive = true,
@@ -265,7 +265,7 @@ namespace MediaBrowser.Api.Movies
                     // Account for duplicates by imdb id, since the database doesn't support this yet
                     // Account for duplicates by imdb id, since the database doesn't support this yet
                     Limit = itemLimit + 2,
                     Limit = itemLimit + 2,
                     PersonTypes = new[] { PersonType.Director },
                     PersonTypes = new[] { PersonType.Director },
-                    IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
+                    IncludeItemTypes = itemTypes.ToArray(),
                     IsMovie = true,
                     IsMovie = true,
                     EnableGroupByMetadataKey = true,
                     EnableGroupByMetadataKey = true,
                     DtoOptions = dtoOptions
                     DtoOptions = dtoOptions
@@ -305,7 +305,7 @@ namespace MediaBrowser.Api.Movies
                     Person = name,
                     Person = name,
                     // Account for duplicates by imdb id, since the database doesn't support this yet
                     // Account for duplicates by imdb id, since the database doesn't support this yet
                     Limit = itemLimit + 2,
                     Limit = itemLimit + 2,
-                    IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
+                    IncludeItemTypes = itemTypes.ToArray(),
                     IsMovie = true,
                     IsMovie = true,
                     EnableGroupByMetadataKey = true,
                     EnableGroupByMetadataKey = true,
                     DtoOptions = dtoOptions
                     DtoOptions = dtoOptions
@@ -343,7 +343,7 @@ namespace MediaBrowser.Api.Movies
                 var similar = _libraryManager.GetItemList(new InternalItemsQuery(user)
                 var similar = _libraryManager.GetItemList(new InternalItemsQuery(user)
                 {
                 {
                     Limit = itemLimit,
                     Limit = itemLimit,
-                    IncludeItemTypes = itemTypes.ToArray(itemTypes.Count),
+                    IncludeItemTypes = itemTypes.ToArray(),
                     IsMovie = true,
                     IsMovie = true,
                     SimilarTo = item,
                     SimilarTo = item,
                     EnableGroupByMetadataKey = true,
                     EnableGroupByMetadataKey = true,

+ 1 - 2
MediaBrowser.Api/SimilarItemsHelper.cs

@@ -11,7 +11,6 @@ using System.Linq;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Services;
 using MediaBrowser.Model.Services;
-using MediaBrowser.Model.Extensions;
 
 
 namespace MediaBrowser.Api
 namespace MediaBrowser.Api
 {
 {
@@ -81,7 +80,7 @@ namespace MediaBrowser.Api
 
 
             var query = new InternalItemsQuery(user)
             var query = new InternalItemsQuery(user)
             {
             {
-                IncludeItemTypes = includeTypes.Select(i => i.Name).ToArray(includeTypes.Length),
+                IncludeItemTypes = includeTypes.Select(i => i.Name).ToArray(),
                 Recursive = true,
                 Recursive = true,
                 DtoOptions = dtoOptions
                 DtoOptions = dtoOptions
             };
             };

+ 1 - 1
MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs

@@ -206,7 +206,7 @@ namespace MediaBrowser.Api.UserLibrary
 
 
             return new QueryResult<BaseItemDto>
             return new QueryResult<BaseItemDto>
             {
             {
-                Items = dtos.ToArray(result.Items.Length),
+                Items = dtos.ToArray(),
                 TotalRecordCount = result.TotalRecordCount
                 TotalRecordCount = result.TotalRecordCount
             };
             };
         }
         }

+ 1 - 1
MediaBrowser.Api/UserLibrary/UserViewsService.cs

@@ -93,7 +93,7 @@ namespace MediaBrowser.Api.UserLibrary
             fields.Add(ItemFields.PrimaryImageAspectRatio);
             fields.Add(ItemFields.PrimaryImageAspectRatio);
             fields.Add(ItemFields.DisplayPreferencesId);
             fields.Add(ItemFields.DisplayPreferencesId);
             fields.Remove(ItemFields.BasicSyncInfo);
             fields.Remove(ItemFields.BasicSyncInfo);
-            dtoOptions.Fields = fields.ToArray(fields.Count);
+            dtoOptions.Fields = fields.ToArray();
 
 
             var user = _userManager.GetUserById(request.UserId);
             var user = _userManager.GetUserById(request.UserId);
 
 

+ 10 - 25
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -1295,7 +1295,7 @@ namespace MediaBrowser.Controller.Entities
                 }
                 }
             }
             }
 
 
-            return string.Join("/", terms.ToArray(terms.Count));
+            return string.Join("/", terms.ToArray());
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -1536,7 +1536,7 @@ namespace MediaBrowser.Controller.Entities
         {
         {
             var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService);
             var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService);
 
 
-            var newThemeVideoIds = newThemeVideos.Select(i => i.Id).ToArray(newThemeVideos.Length);
+            var newThemeVideoIds = newThemeVideos.Select(i => i.Id).ToArray();
 
 
             var themeVideosChanged = !item.ThemeVideoIds.SequenceEqual(newThemeVideoIds);
             var themeVideosChanged = !item.ThemeVideoIds.SequenceEqual(newThemeVideoIds);
 
 
@@ -1573,7 +1573,7 @@ namespace MediaBrowser.Controller.Entities
         private async Task<bool> RefreshThemeSongs(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         private async Task<bool> RefreshThemeSongs(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         {
         {
             var newThemeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService);
             var newThemeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService);
-            var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToArray(newThemeSongs.Length);
+            var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToArray();
 
 
             var themeSongsChanged = !item.ThemeSongIds.SequenceEqual(newThemeSongIds);
             var themeSongsChanged = !item.ThemeSongIds.SequenceEqual(newThemeSongIds);
 
 
@@ -2110,9 +2110,8 @@ namespace MediaBrowser.Controller.Entities
                 }
                 }
                 else
                 else
                 {
                 {
-                    var list = current.ToArray(current.Length + 1);
-                    list[list.Length - 1] = name;
-                    Studios = list;
+                    var list = 
+                    Studios = current.Concat(new [] { name }).ToArray();
                 }
                 }
             }
             }
         }
         }
@@ -2252,9 +2251,7 @@ namespace MediaBrowser.Controller.Entities
             else
             else
             {
             {
                 var currentCount = ImageInfos.Length;
                 var currentCount = ImageInfos.Length;
-                var newList = ImageInfos.ToArray(currentCount + 1);
-                newList[currentCount] = image;
-                ImageInfos = newList;
+                ImageInfos = ImageInfos.Concat(new [] { image }) .ToArray();
             }
             }
         }
         }
 
 
@@ -2269,10 +2266,7 @@ namespace MediaBrowser.Controller.Entities
 
 
             if (image == null)
             if (image == null)
             {
             {
-                var currentCount = ImageInfos.Length;
-                var newList = ImageInfos.ToArray(currentCount + 1);
-                newList[currentCount] = GetImageInfo(file, type);
-                ImageInfos = newList;
+                ImageInfos = ImageInfos.Concat(new [] { GetImageInfo(file, type) }) .ToArray();
             }
             }
             else
             else
             {
             {
@@ -2486,16 +2480,7 @@ namespace MediaBrowser.Controller.Entities
 
 
             if (newImageList.Count > 0)
             if (newImageList.Count > 0)
             {
             {
-                var currentCount = ImageInfos.Length;
-                var newList = ImageInfos.ToArray(currentCount + newImageList.Count);
-
-                foreach (var image in newImageList)
-                {
-                    newList[currentCount] = GetImageInfo(image, imageType);
-                    currentCount++;
-                }
-
-                ImageInfos = newList;
+                ImageInfos = ImageInfos.Concat(newImageList.Select(i => GetImageInfo(i, imageType))).ToArray();
             }
             }
 
 
             return imageUpdated || newImageList.Count > 0;
             return imageUpdated || newImageList.Count > 0;
@@ -2537,7 +2522,7 @@ namespace MediaBrowser.Controller.Entities
             var extensions = new List<string> { ".nfo", ".xml", ".srt", ".vtt", ".sub", ".idx", ".txt", ".edl", ".bif", ".smi", ".ttml" };
             var extensions = new List<string> { ".nfo", ".xml", ".srt", ".vtt", ".sub", ".idx", ".txt", ".edl", ".bif", ".smi", ".ttml" };
             extensions.AddRange(SupportedImageExtensions);
             extensions.AddRange(SupportedImageExtensions);
 
 
-            return FileSystem.GetFiles(FileSystem.GetDirectoryName(Path), extensions.ToArray(extensions.Count), false, false)
+            return FileSystem.GetFiles(FileSystem.GetDirectoryName(Path), extensions.ToArray(), false, false)
                 .Where(i => System.IO.Path.GetFileNameWithoutExtension(i.FullName).StartsWith(filename, StringComparison.OrdinalIgnoreCase))
                 .Where(i => System.IO.Path.GetFileNameWithoutExtension(i.FullName).StartsWith(filename, StringComparison.OrdinalIgnoreCase))
                 .ToList();
                 .ToList();
         }
         }
@@ -2776,7 +2761,7 @@ namespace MediaBrowser.Controller.Entities
         {
         {
             var list = GetEtagValues(user);
             var list = GetEtagValues(user);
 
 
-            return string.Join("|", list.ToArray(list.Count)).GetMD5().ToString("N");
+            return string.Join("|", list.ToArray()).GetMD5().ToString("N");
         }
         }
 
 
         protected virtual List<string> GetEtagValues(User user)
         protected virtual List<string> GetEtagValues(User user)

+ 42 - 0
MediaBrowser.Controller/Entities/BaseItemExtensions.cs

@@ -1,4 +1,5 @@
 using System;
 using System;
+using System.Linq;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
@@ -61,5 +62,46 @@ namespace MediaBrowser.Controller.Entities
                 item.SetImagePath(imageType, BaseItem.FileSystem.GetFileInfo(file));
                 item.SetImagePath(imageType, BaseItem.FileSystem.GetFileInfo(file));
             }
             }
         }
         }
+        
+        /// <summary>
+        /// Copies all properties on object. Skips properties that do not exist.
+        /// </summary>
+        /// <param name="source">The source object.</param>
+        /// <param name="dest">The destination object.</param>
+        public static void DeepCopy<T, TU>(this T source, TU dest) 
+        where T : BaseItem
+        where TU : BaseItem
+        {
+            var sourceProps = typeof (T).GetProperties().Where(x => x.CanRead).ToList();
+            var destProps = typeof(TU).GetProperties()
+                    .Where(x => x.CanWrite)
+                    .ToList();
+
+            foreach (var sourceProp in sourceProps)
+            {
+                if (destProps.Any(x => x.Name == sourceProp.Name))
+                {
+                    var p = destProps.First(x => x.Name == sourceProp.Name);
+                    p.SetValue(dest, sourceProp.GetValue(source, null), null);                    
+                }
+
+            }
+
+        }
+
+        /// <summary>
+        /// Copies all properties on newly created object. Skips properties that do not exist.
+        /// </summary>
+        /// <param name="source">The source object.</param>
+        public static TU DeepCopy<T, TU>(this T source) 
+        where T : BaseItem
+        where TU : BaseItem, new()
+        {
+            var dest = new TU();
+            source.DeepCopy(dest);
+            return dest;
+        }
+
+
     }
     }
 }
 }

+ 1 - 1
MediaBrowser.Controller/Entities/CollectionFolder.cs

@@ -275,7 +275,7 @@ namespace MediaBrowser.Controller.Entities
 
 
             var changed = !linkedChildren.SequenceEqual(LinkedChildren, new LinkedChildComparer(FileSystem));
             var changed = !linkedChildren.SequenceEqual(LinkedChildren, new LinkedChildComparer(FileSystem));
 
 
-            LinkedChildren = linkedChildren.ToArray(linkedChildren.Count);
+            LinkedChildren = linkedChildren.ToArray();
 
 
             var folderIds = PhysicalFolderIds;
             var folderIds = PhysicalFolderIds;
             var newFolderIds = physicalFolders.Select(i => i.Id).ToArray();
             var newFolderIds = physicalFolders.Select(i => i.Id).ToArray();

+ 1 - 4
MediaBrowser.Controller/Entities/Extensions.cs

@@ -35,10 +35,7 @@ namespace MediaBrowser.Controller.Entities
                 }
                 }
                 else
                 else
                 {
                 {
-                    var list = item.RemoteTrailers.ToArray(item.RemoteTrailers.Length + 1);
-                    list[list.Length - 1] = mediaUrl;
-
-                    item.RemoteTrailers = list;
+                    item.RemoteTrailers = item.RemoteTrailers.Concat(new [] { mediaUrl }).ToArray();
                 }
                 }
             }
             }
         }
         }

+ 2 - 2
MediaBrowser.Controller/Entities/Folder.cs

@@ -914,7 +914,7 @@ namespace MediaBrowser.Controller.Entities
                     // Try to preserve order
                     // Try to preserve order
                     return result.OrderBy(i => ids.IndexOf(i.Id)).ToArray();
                     return result.OrderBy(i => ids.IndexOf(i.Id)).ToArray();
                 }
                 }
-                return result.ToArray(result.Count);
+                return result.ToArray();
             }
             }
 
 
             return GetItemsInternal(query).Items;
             return GetItemsInternal(query).Items;
@@ -1608,7 +1608,7 @@ namespace MediaBrowser.Controller.Entities
                     Logger.Info("Shortcut links have changed for {0}", Path);
                     Logger.Info("Shortcut links have changed for {0}", Path);
 
 
                     newShortcutLinks.AddRange(LinkedChildren.Where(i => i.Type == LinkedChildType.Manual));
                     newShortcutLinks.AddRange(LinkedChildren.Where(i => i.Type == LinkedChildType.Manual));
-                    LinkedChildren = newShortcutLinks.ToArray(newShortcutLinks.Count);
+                    LinkedChildren = newShortcutLinks.ToArray();
                     return true;
                     return true;
                 }
                 }
             }
             }

+ 1 - 6
MediaBrowser.Controller/Entities/TagExtensions.cs

@@ -1,7 +1,5 @@
 using System;
 using System;
-using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
-using MediaBrowser.Model.Extensions;
 
 
 namespace MediaBrowser.Controller.Entities
 namespace MediaBrowser.Controller.Entities
 {
 {
@@ -24,10 +22,7 @@ namespace MediaBrowser.Controller.Entities
                 }
                 }
                 else
                 else
                 {
                 {
-                    var list = current.ToArray(current.Length + 1);
-                    list[list.Length - 1] = name;
-
-                    item.Tags = list;
+                    item.Tags = current.Concat(new [] { name }).ToArray();
                 }
                 }
             }
             }
         }
         }

+ 1 - 2
MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs

@@ -6,7 +6,6 @@ using System.Collections.Generic;
 using System.Xml;
 using System.Xml;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Xml;
 using MediaBrowser.Model.Xml;
-using MediaBrowser.Model.Extensions;
 
 
 namespace MediaBrowser.LocalMetadata.Parsers
 namespace MediaBrowser.LocalMetadata.Parsers
 {
 {
@@ -85,7 +84,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
                 }
                 }
             }
             }
 
 
-            item.Item.LinkedChildren = list.ToArray(list.Count);
+            item.Item.LinkedChildren = list.ToArray();
         }
         }
 
 
         public BoxSetXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem)
         public BoxSetXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem)

+ 1 - 1
MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs

@@ -95,7 +95,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
                 }
                 }
             }
             }
 
 
-            item.LinkedChildren = list.ToArray(list.Count);
+            item.LinkedChildren = list.ToArray();
         }
         }
 
 
         public PlaylistXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem)
         public PlaylistXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem)

+ 10 - 23
MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj

@@ -1,33 +1,20 @@
 <Project Sdk="Microsoft.NET.Sdk">
 <Project Sdk="Microsoft.NET.Sdk">
+
   <PropertyGroup>
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
     <TargetFramework>netstandard2.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
   </PropertyGroup>
   </PropertyGroup>
+
   <ItemGroup>
   <ItemGroup>
-    <Compile Include="..\SharedVersion.cs">
-      <Link>Properties\SharedVersion.cs</Link>
-    </Compile>
+    <Compile Include="..\SharedVersion.cs"/>
   </ItemGroup>
   </ItemGroup>
+
   <ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\BDInfo\BDInfo.csproj">
-      <Project>{88ae38df-19d7-406f-a6a9-09527719a21e}</Project>
-      <Name>BDInfo</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
-      <Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
-      <Name>MediaBrowser.Common</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
-      <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
-      <Name>MediaBrowser.Controller</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
-      <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
-      <Name>MediaBrowser.Model</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\OpenSubtitlesHandler\OpenSubtitlesHandler.csproj">
-      <Project>{4a4402d4-e910-443b-b8fc-2c18286a2ca0}</Project>
-      <Name>OpenSubtitlesHandler</Name>
-    </ProjectReference>
+    <ProjectReference Include="..\BDInfo\BDInfo.csproj" />
+    <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
+    <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
+    <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
+    <ProjectReference Include="..\OpenSubtitlesHandler\OpenSubtitlesHandler.csproj" />
   </ItemGroup>
   </ItemGroup>
+
 </Project>
 </Project>

+ 2 - 2
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -246,7 +246,7 @@ namespace MediaBrowser.Model.Configuration
             SortRemoveCharacters = new[] { ",", "&", "-", "{", "}", "'" };
             SortRemoveCharacters = new[] { ",", "&", "-", "{", "}", "'" };
             SortRemoveWords = new[] { "the", "a", "an" };
             SortRemoveWords = new[] { "the", "a", "an" };
 
 
-            UICulture = "en-us";
+            UICulture = "en-US";
 
 
             MetadataOptions = new[]
             MetadataOptions = new[]
             {
             {
@@ -310,4 +310,4 @@ namespace MediaBrowser.Model.Configuration
         public string From { get; set; }
         public string From { get; set; }
         public string To { get; set; }
         public string To { get; set; }
     }
     }
-}
+}

+ 1 - 1
MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs

@@ -101,7 +101,7 @@ namespace MediaBrowser.Model.Dlna
                 {
                 {
                     list.Add(MediaFormatProfile.MPEG_TS_JP_T);
                     list.Add(MediaFormatProfile.MPEG_TS_JP_T);
                 }
                 }
-                return list.ToArray(list.Count);
+                return list.ToArray();
             }
             }
             if (StringHelper.EqualsIgnoreCase(videoCodec, "h264"))
             if (StringHelper.EqualsIgnoreCase(videoCodec, "h264"))
             {
             {

+ 1 - 1
MediaBrowser.Model/Dlna/StreamInfo.cs

@@ -186,7 +186,7 @@ namespace MediaBrowser.Model.Dlna
                 list.Add(string.Format("{0}={1}", pair.Name, encodedValue));
                 list.Add(string.Format("{0}={1}", pair.Name, encodedValue));
             }
             }
 
 
-            string queryString = string.Join("&", list.ToArray(list.Count));
+            string queryString = string.Join("&", list.ToArray());
 
 
             return GetUrl(baseUrl, queryString);
             return GetUrl(baseUrl, queryString);
         }
         }

+ 4 - 3
MediaBrowser.Model/Entities/MediaStream.cs

@@ -1,4 +1,5 @@
 using System;
 using System;
+using System.Linq;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.Extensions;
@@ -104,7 +105,7 @@ namespace MediaBrowser.Model.Entities
                         attributes.Add("Default");
                         attributes.Add("Default");
                     }
                     }
 
 
-                    return string.Join(" ", attributes.ToArray(attributes.Count));
+                    return string.Join(" ", attributes.ToArray());
                 }
                 }
 
 
                 if (Type == MediaStreamType.Video)
                 if (Type == MediaStreamType.Video)
@@ -123,7 +124,7 @@ namespace MediaBrowser.Model.Entities
                         attributes.Add(Codec.ToUpper());
                         attributes.Add(Codec.ToUpper());
                     }
                     }
 
 
-                    return string.Join(" ", attributes.ToArray(attributes.Count));
+                    return string.Join(" ", attributes.ToArray());
                 }
                 }
 
 
                 if (Type == MediaStreamType.Subtitle)
                 if (Type == MediaStreamType.Subtitle)
@@ -154,7 +155,7 @@ namespace MediaBrowser.Model.Entities
                         attributes.Add("Forced");
                         attributes.Add("Forced");
                     }
                     }
 
 
-                    string name = string.Join(" ", attributes.ToArray(attributes.Count));
+                    string name = string.Join(" ", attributes.ToArray());
 
 
                     return name;
                     return name;
                 }
                 }

+ 1 - 13
MediaBrowser.Model/Extensions/LinqExtensions.cs

@@ -1,6 +1,7 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 
 
+// TODO: @bond Remove
 namespace MediaBrowser.Model.Extensions
 namespace MediaBrowser.Model.Extensions
 {
 {
     // MoreLINQ - Extensions to LINQ to Objects
     // MoreLINQ - Extensions to LINQ to Objects
@@ -42,19 +43,6 @@ namespace MediaBrowser.Model.Extensions
             return source.DistinctBy(keySelector, null);
             return source.DistinctBy(keySelector, null);
         }
         }
 
 
-        public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source, int count)
-        {
-            if (source == null) throw new ArgumentNullException("source");
-            if (count < 0) throw new ArgumentOutOfRangeException("count");
-            var array = new TSource[count];
-            int i = 0;
-            foreach (var item in source)
-            {
-                array[i++] = item;
-            }
-            return array;
-        }
-
         /// <summary>
         /// <summary>
         /// Returns all distinct elements of the given source, where "distinctness"
         /// Returns all distinct elements of the given source, where "distinctness"
         /// is determined via a projection and the specified comparer for the projected type.
         /// is determined via a projection and the specified comparer for the projected type.

+ 1 - 3
MediaBrowser.Model/Services/HttpUtility.cs

@@ -2,8 +2,6 @@
 using System.Collections;
 using System.Collections;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Text;
 using System.Text;
-using MediaBrowser.Model.Services;
-using MediaBrowser.Model.Extensions;
 
 
 namespace MediaBrowser.Model.Services
 namespace MediaBrowser.Model.Services
 {
 {
@@ -586,7 +584,7 @@ namespace MediaBrowser.Model.Services
                     WriteCharBytes(bytes, ch, e);
                     WriteCharBytes(bytes, ch, e);
             }
             }
 
 
-            byte[] buf = bytes.ToArray(bytes.Count);
+            byte[] buf = bytes.ToArray();
             bytes = null;
             bytes = null;
             return e.GetString(buf, 0, buf.Length);
             return e.GetString(buf, 0, buf.Length);
 
 

+ 1 - 2
MediaBrowser.Model/Services/QueryParamCollection.cs

@@ -2,7 +2,6 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Extensions;
 
 
 namespace MediaBrowser.Model.Services
 namespace MediaBrowser.Model.Services
 {
 {
@@ -221,7 +220,7 @@ namespace MediaBrowser.Model.Services
 
 
         public override String ToString()
         public override String ToString()
         {
         {
-            var vals = this.Select(GetQueryStringValue).ToArray(this.Count);
+            var vals = this.Select(GetQueryStringValue).ToArray();
 
 
             return string.Join("&", vals);
             return string.Join("&", vals);
         }
         }

+ 1 - 1
MediaBrowser.Providers/Manager/ImageSaver.cs

@@ -551,7 +551,7 @@ namespace MediaBrowser.Providers.Manager
                 {
                 {
                     list.Add(Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(UsCulture) + extension));
                     list.Add(Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(UsCulture) + extension));
                 }
                 }
-                return list.ToArray(list.Count);
+                return list.ToArray();
             }
             }
 
 
             if (type == ImageType.Primary)
             if (type == ImageType.Primary)

+ 2 - 2
MediaBrowser.Providers/Manager/ProviderManager.cs

@@ -522,7 +522,7 @@ namespace MediaBrowser.Providers.Manager
                 Type = MetadataPluginType.SubtitleFetcher
                 Type = MetadataPluginType.SubtitleFetcher
             }));
             }));
 
 
-            summary.Plugins = pluginList.ToArray(pluginList.Count);
+            summary.Plugins = pluginList.ToArray();
 
 
             var supportedImageTypes = imageProviders.OfType<IRemoteImageProvider>()
             var supportedImageTypes = imageProviders.OfType<IRemoteImageProvider>()
                 .SelectMany(i => i.GetSupportedImages(dummy))
                 .SelectMany(i => i.GetSupportedImages(dummy))
@@ -1160,4 +1160,4 @@ namespace MediaBrowser.Providers.Manager
             }
             }
         }
         }
     }
     }
-}
+}

+ 1 - 1
MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs

@@ -145,7 +145,7 @@ namespace MediaBrowser.Providers.Movies
                 movie.ProductionLocations = movieData
                 movie.ProductionLocations = movieData
                     .production_countries
                     .production_countries
                     .Select(i => i.name)
                     .Select(i => i.name)
-                    .ToArray(movieData.production_countries.Count);
+                    .ToArray();
             }
             }
 
 
             movie.SetProviderId(MetadataProviders.Tmdb, movieData.id.ToString(_usCulture));
             movie.SetProviderId(MetadataProviders.Tmdb, movieData.id.ToString(_usCulture));

+ 1 - 1
MediaBrowser.Providers/Movies/MovieDbProvider.cs

@@ -279,7 +279,7 @@ namespace MediaBrowser.Providers.Movies
                 languages.Add("en");
                 languages.Add("en");
             }
             }
 
 
-            return string.Join(",", languages.ToArray(languages.Count));
+            return string.Join(",", languages.ToArray());
         }
         }
 
 
         public static string NormalizeLanguage(string language)
         public static string NormalizeLanguage(string language)

+ 1 - 2
MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs

@@ -17,7 +17,6 @@ using System.Threading.Tasks;
 using System.Xml;
 using System.Xml;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Xml;
 using MediaBrowser.Model.Xml;
-using MediaBrowser.Model.Extensions;
 
 
 namespace MediaBrowser.Providers.Music
 namespace MediaBrowser.Providers.Music
 {
 {
@@ -846,4 +845,4 @@ namespace MediaBrowser.Providers.Music
             public int throttleMs { get; set; }
             public int throttleMs { get; set; }
         }
         }
     }
     }
-}
+}

+ 1 - 1
MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs

@@ -236,7 +236,7 @@ namespace MediaBrowser.Providers.TV
 
 
             if (seriesInfo.networks != null)
             if (seriesInfo.networks != null)
             {
             {
-                series.Studios = seriesInfo.networks.Select(i => i.name).ToArray(seriesInfo.networks.Count);
+                series.Studios = seriesInfo.networks.Select(i => i.name).ToArray();
             }
             }
 
 
             if (seriesInfo.genres != null)
             if (seriesInfo.genres != null)

+ 1 - 1
Mono.Nat/Pmp/PmpNatDevice.cs

@@ -95,7 +95,7 @@ namespace Mono.Nat.Pmp
 
 
             try
             try
             {
             {
-                byte[] buffer = package.ToArray(package.Count);
+                byte[] buffer = package.ToArray();
                 int attempt = 0;
                 int attempt = 0;
                 int delay = PmpConstants.RetryDelay;
                 int delay = PmpConstants.RetryDelay;
 
 

+ 110 - 0
build-jellyfin.ps1

@@ -0,0 +1,110 @@
+[CmdletBinding()]
+param(
+    [switch]$InstallFFMPEG,
+    [switch]$InstallNSSM,
+    [switch]$GenerateZip,
+    [string]$InstallLocation = "$Env:AppData/Jellyfin-Server/",
+    [ValidateSet('Debug','Release')][string]$BuildType = 'Release',
+    [ValidateSet('Quiet','Minimal', 'Normal')][string]$DotNetVerbosity = 'Minimal',
+    [ValidateSet('win','win7', 'win8','win81','win10')][string]$WindowsVersion = 'win',
+    [ValidateSet('x64','x86', 'arm', 'arm64')][string]$Architecture = 'x64'
+)
+
+#PowershellCore and *nix check to make determine which temp dir to use.
+if(($PSVersionTable.PSEdition -eq 'Core') -and (-not $IsWindows)){
+    $TempDir = mktemp -d
+}else{
+    $TempDir = $env:Temp
+}
+
+function Build-JellyFin {
+    if(($Architecture -eq 'arm64') -and ($WindowsVersion -ne 'win10')){
+            Write-Error "arm64 only supported with Windows10 Version"
+            exit
+        }
+    if(($Architecture -eq 'arm') -and ($WindowsVersion -notin @('win10','win81','win8'))){
+            Write-Error "arm only supported with Windows 8 or higher"
+            exit
+        }
+    dotnet publish -c $BuildType -r "$windowsversion-$Architecture" MediaBrowser.sln -o $InstallLocation -v $DotNetVerbosity
+}
+
+function Install-FFMPEG {
+    param(
+        [string]$InstallLocation,
+        [string]$Architecture
+    )
+    Write-Verbose "Checking Architecture"
+    if($Architecture -notin @('x86','x64')){
+        Write-Warning "No builds available for your selected architecture of $Architecture"
+        Write-Warning "FFMPEG will not be installed" 
+    }elseif($Architecture -eq 'x64'){
+         Write-Verbose "Downloading 64 bit FFMPEG"
+         Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-4.1-win64-static.zip -UseBasicParsing -OutFile "$tempdir/fmmpeg.zip" | Write-Verbose
+    }else{
+         Write-Verbose "Downloading 32 bit FFMPEG"
+         Invoke-WebRequest -Uri https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-4.1-win32-static.zip -UseBasicParsing -OutFile "$tempdir/fmmpeg.zip" | Write-Verbose
+    }
+   
+    Expand-Archive "$tempdir/fmmpeg.zip" -DestinationPath "$tempdir/ffmpeg/" | Write-Verbose
+    if($Architecture -eq 'x64'){
+        Write-Verbose "Copying Binaries to Jellyfin location"
+        Get-ChildItem "$tempdir/ffmpeg/ffmpeg-4.1-win64-static/bin" | ForEach-Object {
+            Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
+        }
+    }else{
+        Write-Verbose "Copying Binaries to Jellyfin location"
+        Get-ChildItem "$tempdir/ffmpeg/ffmpeg-4.1-win32-static/bin" | ForEach-Object {
+            Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
+        }
+    }
+    Remove-Item "$tempdir/ffmpeg/" -Recurse -Force -ErrorAction Continue | Write-Verbose
+    Remove-Item "$tempdir/fmmpeg.zip" -Force -ErrorAction Continue | Write-Verbose
+}
+
+function Install-NSSM {
+    param(
+        [string]$InstallLocation,
+        [string]$Architecture
+    )
+    Write-Verbose "Checking Architecture"
+    if($Architecture -notin @('x86','x64')){
+        Write-Warning "No builds available for your selected architecture of $Architecture"
+        Write-Warning "NSSM will not be installed" 
+    }else{
+         Write-Verbose "Downloading NSSM"
+         Invoke-WebRequest -Uri https://nssm.cc/ci/nssm-2.24-101-g897c7ad.zip -UseBasicParsing -OutFile "$tempdir/nssm.zip" | Write-Verbose
+    }
+   
+    Expand-Archive "$tempdir/nssm.zip" -DestinationPath "$tempdir/nssm/" | Write-Verbose
+    if($Architecture -eq 'x64'){
+        Write-Verbose "Copying Binaries to Jellyfin location"
+        Get-ChildItem "$tempdir/nssm/nssm-2.24-101-g897c7ad/win64" | ForEach-Object {
+            Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
+        }
+    }else{
+        Write-Verbose "Copying Binaries to Jellyfin location"
+        Get-ChildItem "$tempdir/nssm/nssm-2.24-101-g897c7ad/win32" | ForEach-Object {
+            Copy-Item $_.FullName -Destination $installLocation | Write-Verbose
+        }
+    }
+    Remove-Item "$tempdir/nssm/" -Recurse -Force -ErrorAction Continue | Write-Verbose
+    Remove-Item "$tempdir/nssm.zip" -Force -ErrorAction Continue | Write-Verbose
+}
+
+Write-Verbose "Starting Build Process: Selected Environment is $WindowsVersion-$Architecture"
+Build-JellyFin
+if($InstallFFMPEG.IsPresent -or ($InstallFFMPEG -eq $true)){
+    Write-Verbose "Starting FFMPEG Install"
+    Install-FFMPEG $InstallLocation $Architecture
+}
+if($InstallNSSM.IsPresent -or ($InstallNSSM -eq $true)){
+    Write-Verbose "Starting NSSM Install"
+    Install-NSSM $InstallLocation $Architecture
+}
+Copy-Item .\install-jellyfin.ps1 $InstallLocation\install-jellyfin.ps1
+Copy-Item .\installjellyfin.bat $InstallLocation\installjellyfin.bat
+if($GenerateZip.IsPresent -or ($GenerateZip -eq $true)){
+    Compress-Archive -Path $InstallLocation -DestinationPath "$InstallLocation/jellyfin.zip" -Force
+}
+Write-Verbose "Finished"

+ 7 - 0
debian/changelog

@@ -1,3 +1,10 @@
+jellyfin (3.5.2-5) unstable; urgency=medium
+
+  * Fully GPL'd release - remove tainted code from MediaBrowser.Common
+  * Several code cleanups and tweaks
+
+ -- Joshua Boniface <joshua@boniface.me>  Fri, 28 Dec 2018 10:26:30 -0500
+
 jellyfin (3.5.2-4) unstable; urgency=medium
 jellyfin (3.5.2-4) unstable; urgency=medium
 
 
   * Correct manifest.json bug and vdpau
   * Correct manifest.json bug and vdpau

+ 2 - 2
debian/jellyfin.service

@@ -7,8 +7,8 @@ Type = simple
 EnvironmentFile = /etc/default/jellyfin
 EnvironmentFile = /etc/default/jellyfin
 User = jellyfin
 User = jellyfin
 ExecStart = /usr/bin/jellyfin -programdata ${JELLYFIN_DATA} -restartpath ${JELLYFIN_RESTART_SCRIPT} ${JELLYFIN_ADD_OPTS}
 ExecStart = /usr/bin/jellyfin -programdata ${JELLYFIN_DATA} -restartpath ${JELLYFIN_RESTART_SCRIPT} ${JELLYFIN_ADD_OPTS}
-Restart = on-abort
-TimeoutSec = 20
+Restart = on-failure
+TimeoutSec = 15
 
 
 [Install]
 [Install]
 WantedBy = multi-user.target
 WantedBy = multi-user.target

+ 2 - 1
debian/rules

@@ -2,6 +2,7 @@
 CONFIG := Release
 CONFIG := Release
 TERM := xterm
 TERM := xterm
 SHELL := /bin/bash
 SHELL := /bin/bash
+DOTNETRUNTIME := linux-x64
 export DH_VERBOSE=1
 export DH_VERBOSE=1
 export DOTNET_CLI_TELEMETRY_OPTOUT=1
 export DOTNET_CLI_TELEMETRY_OPTOUT=1
 
 
@@ -15,7 +16,7 @@ override_dh_auto_test:
 override_dh_clistrip:
 override_dh_clistrip:
 
 
 override_dh_auto_build:
 override_dh_auto_build:
-	dotnet publish --configuration $(CONFIG) --output='$(CURDIR)/usr/lib/jellyfin/bin' --self-contained --runtime linux-x64
+	dotnet publish --configuration $(CONFIG) --output='$(CURDIR)/usr/lib/jellyfin/bin' --self-contained --runtime $(DOTNETRUNTIME)
 
 
 override_dh_auto_clean:
 override_dh_auto_clean:
 	dotnet clean -maxcpucount:1 --configuration $(CONFIG) || true
 	dotnet clean -maxcpucount:1 --configuration $(CONFIG) || true

+ 460 - 0
install-jellyfin.ps1

@@ -0,0 +1,460 @@
+[CmdletBinding()]
+
+param(
+    [Switch]$Quiet,
+    [Switch]$InstallAsService,
+    [pscredential]$ServiceUser,
+    [switch]$CreateDesktopShorcut,
+    [switch]$LaunchJellyfin,
+    [switch]$MigrateEmbyLibrary,
+    [string]$InstallLocation,
+    [string]$EmbyLibraryLocation,
+    [string]$JellyfinLibraryLocation
+)
+<# This form was created using POSHGUI.com  a free online gui designer for PowerShell
+.NAME
+    Install-Jellyfin
+#>
+
+#This doesn't need to be used by default anymore, but I am keeping it in as a function for future use.
+function Elevate-Window {
+    # Get the ID and security principal of the current user account
+    $myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
+    $myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
+ 
+    # Get the security principal for the Administrator role
+    $adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
+ 
+    # Check to see if we are currently running "as Administrator"
+    if ($myWindowsPrincipal.IsInRole($adminRole))
+    {
+        # We are running "as Administrator" - so change the title and background color to indicate this
+        $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)"
+        $Host.UI.RawUI.BackgroundColor = "DarkBlue"
+        clear-host
+    }
+    else
+    {
+        # We are not running "as Administrator" - so relaunch as administrator
+   
+        # Create a new process object that starts PowerShell
+        $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";
+   
+        # Specify the current script path and name as a parameter
+        $newProcess.Arguments = $myInvocation.MyCommand.Definition;
+   
+        # Indicate that the process should be elevated
+        $newProcess.Verb = "runas";
+   
+        # Start the new process
+        [System.Diagnostics.Process]::Start($newProcess);
+   
+        # Exit from the current, unelevated, process
+        exit
+    }
+}
+
+#FIXME The install methods should be a function that takes all the params, the quiet flag should be a paramset
+
+if($Quiet.IsPresent -or $Quiet -eq $true){
+    if([string]::IsNullOrEmpty($JellyfinLibraryLocation)){
+        $Script:JellyfinDataDir = "$env:AppData\jellyfin\"
+    }else{
+        $Script:JellyfinDataDir = $JellyfinLibraryLocation
+    }
+    if([string]::IsNullOrEmpty($InstallLocation)){
+        $Script:DefaultJellyfinInstallDirectory = "$env:Appdata\jellyfin\"
+    }else{
+        $Script:DefaultJellyfinInstallDirectory = $InstallLocation
+    }
+    
+    if([string]::IsNullOrEmpty($EmbyLibraryLocation)){
+        $Script:defaultEmbyDataDir = "$env:Appdata\Emby-Server\data\"
+    }else{
+        $Script:defaultEmbyDataDir = $EmbyLibraryLocation
+    }
+    
+    if($InstallAsService.IsPresent -or $InstallAsService -eq $true){
+        $Script:InstallAsService = $true  
+    }else{$Script:InstallAsService = $false}
+    if($null -eq $ServiceUser){
+        $Script:InstallServiceAsUser = $false
+    }else{
+        $Script:InstallServiceAsUser = $true
+        $Script:UserCredentials = $ServiceUser
+        $Script:JellyfinDataDir = "C:\Users\$($Script:UserCredentials.UserName)\Appdata\Roaming\jellyfin\"}
+    if($CreateDesktopShorcut.IsPresent -or $CreateDesktopShorcut -eq $true) {$Script:CreateShortcut = $true}else{$Script:CreateShortcut = $false}
+    if($MigrateEmbyLibrary.IsPresent -or $MigrateEmbyLibrary -eq $true){$Script:MigrateLibrary = $true}else{$Script:MigrateLibrary = $false}
+    if($LaunchJellyfin.IsPresent -or $LaunchJellyfin -eq $true){$Script:StartJellyfin = $true}else{$Script:StartJellyfin = $false}
+    
+    if(-not (Test-Path $Script:DefaultJellyfinInstallDirectory)){
+        mkdir $Script:DefaultJellyfinInstallDirectory
+    }
+    Copy-Item -Path $PSScriptRoot/* -DestinationPath "$Script:DefaultJellyfinInstallDirectory/" -Force -Recurse
+    if($Script:InstallAsService){
+        if($Script:InstallServiceAsUser){
+            &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
+            Start-Sleep -Milliseconds 500
+            &sc.exe config Jellyfin obj=".\$($Script:UserCredentials.UserName)" password="$($Script:UserCredentials.GetNetworkCredential().Password)"
+            &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START 
+        }else{
+            &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
+            Start-Sleep -Milliseconds 500
+            #&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin ObjectName $Script:UserCredentials.UserName $Script:UserCredentials.GetNetworkCredential().Password
+            #Set-Service -Name Jellyfin -Credential $Script:UserCredentials
+            &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START 
+        }
+    }
+    if($Script:MigrateLibrary){
+        Copy-Item -Path $Script:defaultEmbyDataDir/config -Destination $Script:JellyfinDataDir -force -Recurse
+        Copy-Item -Path $Script:defaultEmbyDataDir/cache -Destination $Script:JellyfinDataDir -force -Recurse
+        Copy-Item -Path $Script:defaultEmbyDataDir/data -Destination $Script:JellyfinDataDir -force -Recurse
+        Copy-Item -Path $Script:defaultEmbyDataDir/metadata -Destination $Script:JellyfinDataDir -force -Recurse
+        Copy-Item -Path $Script:defaultEmbyDataDir/root -Destination $Script:JellyfinDataDir -force -Recurse
+    }
+    if($Script:CreateShortcut){
+        $WshShell = New-Object -comObject WScript.Shell
+        $Shortcut = $WshShell.CreateShortcut("$Home\Desktop\Jellyfin.lnk")
+        $Shortcut.TargetPath = "$Script:DefaultJellyfinInstallDirectory\jellyfin.exe"
+        $Shortcut.Save()
+    }
+    if($Script:StartJellyfin){
+        if($Script:InstallAsService){
+            Get-Service Jellyfin | Start-Service
+        }else{
+            Start-Process -FilePath $Script:DefaultJellyfinInstallDirectory\jellyfin.exe -PassThru
+        }
+    }
+}else{
+
+}
+Add-Type -AssemblyName System.Windows.Forms
+[System.Windows.Forms.Application]::EnableVisualStyles()
+
+$Script:JellyFinDataDir = "$env:AppData\jellyfin\"
+$Script:DefaultJellyfinInstallDirectory = "$env:Appdata\jellyfin\"
+$Script:defaultEmbyDataDir = "$env:Appdata\Emby-Server\"
+$Script:InstallAsService = $False
+$Script:InstallServiceAsUser = $false
+$Script:CreateShortcut = $false
+$Script:MigrateLibrary = $false
+$Script:StartJellyfin = $false
+
+function InstallJellyfin {
+    Write-Host "Install as service: $Script:InstallAsService" 
+    Write-Host "Install as serviceuser: $Script:InstallServiceAsUser"
+    Write-Host "Create Shortcut: $Script:CreateShortcut"
+    Write-Host "MigrateLibrary: $Script:MigrateLibrary"
+    $GUIElementsCollection | ForEach-Object {
+        $_.Enabled = $false
+    }
+    Write-Host "Making Jellyfin directory"
+    $ProgressBar.Minimum = 1
+    $ProgressBar.Maximum = 100
+    $ProgressBar.Value = 1
+    if($Script:DefaultJellyfinInstallDirectory -ne $InstallLocationBox.Text){
+        Write-Host "Custom Install Location Chosen: $($InstallLocationBox.Text)"
+        $Script:DefaultJellyfinInstallDirectory = $InstallLocationBox.Text
+    }
+    if($Script:JellyfinDataDir -ne $CustomLibraryBox.Text){
+        Write-Host "Custom Library Location Chosen: $($CustomLibraryBox.Text)"
+        $Script:JellyfinDataDir = $CustomLibraryBox.Text
+    }
+    if(-not (Test-Path $Script:DefaultJellyfinInstallDirectory)){
+        mkdir $Script:DefaultJellyfinInstallDirectory
+    }
+    Write-Host "Copying Jellyfin Data"
+    $progressbar.Value = 10 
+    Copy-Item -Path $PSScriptRoot/* -Destination $Script:DefaultJellyfinInstallDirectory/ -Force -Recurse
+    Write-Host "Finished Copying"
+    $ProgressBar.Value = 50
+    if($Script:InstallAsService){
+        if($Script:InstallServiceAsUser){
+            Write-Host "Installing Service as user $($Script:UserCredentials.UserName)"
+            &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
+            Start-Sleep -Milliseconds 2000
+            &sc.exe config Jellyfin obj=".\$($Script:UserCredentials.UserName)" password="$($Script:UserCredentials.GetNetworkCredential().Password)"
+            &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START 
+        }else{
+            Write-Host "Installing Service as LocalSystem"
+            &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`"
+            Start-Sleep -Milliseconds 2000
+            &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START 
+        }
+    }
+    $progressbar.Value = 60
+    if($Script:MigrateLibrary){
+        if($Script:defaultEmbyDataDir -ne $LibraryLocationBox.Text){
+           Write-Host "Custom location defined for emby library: $($LibraryLocationBox.Text)"
+           $Script:defaultEmbyDataDir = $LibraryLocationBox.Text
+        }
+        Write-Host "Copying emby library from $Script:defaultEmbyDataDir to $Script:JellyFinDataDir"
+        Write-Host "This could take a while depending on the size of your library. Please be patient"
+        Write-Host "Copying config"
+        Copy-Item -Path $Script:defaultEmbyDataDir/config -Destination $Script:JellyfinDataDir -force -Recurse
+        Write-Host "Copying cache"
+        Copy-Item -Path $Script:defaultEmbyDataDir/cache -Destination $Script:JellyfinDataDir -force -Recurse
+        Write-Host "Copying data"
+        Copy-Item -Path $Script:defaultEmbyDataDir/data -Destination $Script:JellyfinDataDir -force -Recurse
+        Write-Host "Copying metadata"
+        Copy-Item -Path $Script:defaultEmbyDataDir/metadata -Destination $Script:JellyfinDataDir -force -Recurse
+        Write-Host "Copying root dir"
+        Copy-Item -Path $Script:defaultEmbyDataDir/root -Destination $Script:JellyfinDataDir  -force -Recurse
+    }
+    $progressbar.Value = 80
+    if($Script:CreateShortcut){
+        Write-Host "Creating Shortcut"
+        $WshShell = New-Object -comObject WScript.Shell
+        $Shortcut = $WshShell.CreateShortcut("$Home\Desktop\Jellyfin.lnk")
+        $Shortcut.TargetPath = "$Script:DefaultJellyfinInstallDirectory\jellyfin.exe"
+        $Shortcut.Save()
+    }
+    $ProgressBar.Value = 90
+    if($Script:StartJellyfin){
+        if($Script:InstallAsService){
+            Write-Host "Starting Jellyfin Service"
+            Get-Service Jellyfin | Start-Service
+        }else{
+            Write-Host "Starting Jellyfin"
+            Start-Process -FilePath $Script:DefaultJellyfinInstallDirectory\jellyfin.exe -PassThru
+        }
+    }
+    $progressbar.Value = 100
+    Write-Host Finished
+    $wshell = New-Object -ComObject Wscript.Shell
+    $wshell.Popup("Operation Completed",0,"Done",0x1)
+    $InstallForm.Close()
+}
+function ServiceBoxCheckChanged {
+    if($InstallAsServiceCheck.Checked){
+        $Script:InstallAsService         = $true
+        $ServiceUserLabel.Visible = $true
+        $ServiceUserLabel.Enabled = $true
+        $ServiceUserBox.Visible = $true
+        $ServiceUserBox.Enabled = $true
+    }else{
+        $Script:InstallAsService         = $false
+        $ServiceUserLabel.Visible = $false
+        $ServiceUserLabel.Enabled = $false
+        $ServiceUserBox.Visible = $false
+        $ServiceUserBox.Enabled = $false
+    }
+}
+function UserSelect {
+    if($ServiceUserBox.Text -eq 'Local System')
+    {
+        $Script:InstallServiceAsUser = $false
+         $Script:UserCredentials = $null
+         $ServiceUserBox.Items.RemoveAt(1)
+         $ServiceUserBox.Items.Add("Custom User")
+    }elseif($ServiceUserBox.Text -eq 'Custom User'){
+        $Script:InstallServiceAsUser = $true
+        $Script:UserCredentials = Get-Credential -Message "Please enter the credentials of the user you with to run Jellyfin Service as" -UserName $env:USERNAME
+        $ServiceUserBox.Items[1] = "$($Script:UserCredentials.UserName)"
+    }
+}
+function CreateShortcutBoxCheckChanged {
+    if($CreateShortcutCheck.Checked){
+        $Script:CreateShortcut = $true
+    }else{
+        $Script:CreateShortcut = $False
+    }
+}
+function StartJellyFinBoxCheckChanged {
+    if($StartProgramCheck.Checked){
+        $Script:StartJellyfin = $true
+    }else{
+        $Script:StartJellyfin = $false
+    }
+}
+
+function CustomLibraryCheckChanged {
+    if($CustomLibraryCheck.Checked){
+        $Script:UseCustomLibrary = $true
+        $CustomLibraryBox.Enabled = $true
+    }else{
+        $Script:UseCustomLibrary = $false
+        $CustomLibraryBox.Enabled = $false
+    }
+}
+
+function MigrateLibraryCheckboxChanged {
+
+    if($MigrateLibraryCheck.Checked){
+        $Script:MigrateLibrary         = $true
+        $LibraryMigrationLabel.Visible = $true
+        $LibraryMigrationLabel.Enabled = $true
+        $LibraryLocationBox.Visible = $true
+        $LibraryLocationBox.Enabled = $true
+    }else{
+        $Script:MigrateLibrary         = $false
+        $LibraryMigrationLabel.Visible = $false
+        $LibraryMigrationLabel.Enabled = $false
+        $LibraryLocationBox.Visible = $false
+        $LibraryLocationBox.Enabled = $false
+    }
+
+}
+
+
+#region begin GUI{ 
+
+$InstallForm                     = New-Object system.Windows.Forms.Form
+$InstallForm.ClientSize          = '320,240'
+$InstallForm.text                = "Terrible Jellyfin Installer"
+$InstallForm.TopMost             = $false
+
+$GUIElementsCollection = @()
+
+$InstallButton                   = New-Object system.Windows.Forms.Button
+$InstallButton.text              = "Install"
+$InstallButton.width             = 60
+$InstallButton.height            = 30
+$InstallButton.location          = New-Object System.Drawing.Point(5,5)
+$InstallButton.Font              = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $InstallButton
+
+$ProgressBar                     = New-Object system.Windows.Forms.ProgressBar
+$ProgressBar.width               = 245
+$ProgressBar.height              = 30
+$ProgressBar.location            = New-Object System.Drawing.Point(70,5)
+
+$InstallLocationLabel            = New-Object system.Windows.Forms.Label
+$InstallLocationLabel.text       = "Install Location"
+$InstallLocationLabel.TextAlign  = [System.Drawing.ContentAlignment]::MiddleLeft
+$InstallLocationLabel.AutoSize   = $true
+$InstallLocationLabel.width      = 100
+$InstallLocationLabel.height     = 20
+$InstallLocationLabel.location   = New-Object System.Drawing.Point(5,50)
+$InstallLocationLabel.Font       = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $InstallLocationLabel
+
+$InstallLocationBox              = New-Object system.Windows.Forms.TextBox
+$InstallLocationBox.multiline    = $false
+$InstallLocationBox.width        = 205
+$InstallLocationBox.height       = 20
+$InstallLocationBox.location     = New-Object System.Drawing.Point(110,50)
+$InstallLocationBox.Text            = $Script:DefaultJellyfinInstallDirectory
+$InstallLocationBox.Font         = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $InstallLocationBox
+
+$CustomLibraryCheck                       = New-Object system.Windows.Forms.CheckBox
+$CustomLibraryCheck.text                  = "Custom Library Location:"
+$CustomLibraryCheck.TextAlign  = [System.Drawing.ContentAlignment]::MiddleLeft
+$CustomLibraryCheck.AutoSize              = $false
+$CustomLibraryCheck.width                 = 180
+$CustomLibraryCheck.height                = 20
+$CustomLibraryCheck.location              = New-Object System.Drawing.Point(5,75)
+$CustomLibraryCheck.Font                  = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $CustomLibraryCheck
+
+$CustomLibraryBox              = New-Object system.Windows.Forms.TextBox
+$CustomLibraryBox.multiline    = $false
+$CustomLibraryBox.width        = 130
+$CustomLibraryBox.height       = 20
+$CustomLibraryBox.location     = New-Object System.Drawing.Point(185,75)
+$CustomLibraryBox.Text            = $Script:JellyFinDataDir
+$CustomLibraryBox.Font         = 'Microsoft Sans Serif,10'
+$CustomLibraryBox.Enabled      = $false
+$GUIElementsCollection += $CustomLibraryBox
+
+$InstallAsServiceCheck                       = New-Object system.Windows.Forms.CheckBox
+$InstallAsServiceCheck.text                  = "Install as Service"
+$InstallAsServiceCheck.AutoSize              = $false
+$InstallAsServiceCheck.width                 = 140
+$InstallAsServiceCheck.height                = 20
+$InstallAsServiceCheck.location              = New-Object System.Drawing.Point(5,125)
+$InstallAsServiceCheck.Font                  = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $InstallAsServiceCheck
+
+$ServiceUserLabel            = New-Object system.Windows.Forms.Label
+$ServiceUserLabel.text       = "Run Service As:"
+$ServiceUserLabel.AutoSize   = $true
+$ServiceUserLabel.TextAlign  = [System.Drawing.ContentAlignment]::MiddleLeft
+$ServiceUserLabel.width      = 100
+$ServiceUserLabel.height     = 20
+$ServiceUserLabel.location   = New-Object System.Drawing.Point(15,145)
+$ServiceUserLabel.Font       = 'Microsoft Sans Serif,10'
+$ServiceUserLabel.Visible    = $false
+$ServiceUserLabel.Enabled    = $false
+$GUIElementsCollection += $ServiceUserLabel
+
+$ServiceUserBox                  = New-Object system.Windows.Forms.ComboBox
+$ServiceUserBox.text             = "Run Service As"
+$ServiceUserBox.width            = 195
+$ServiceUserBox.height           = 20
+@('Local System','Custom User') | ForEach-Object {[void] $ServiceUserBox.Items.Add($_)}
+$ServiceUserBox.location         = New-Object System.Drawing.Point(120,145)
+$ServiceUserBox.Font             = 'Microsoft Sans Serif,10'
+$ServiceUserBox.Visible          = $false
+$ServiceUserBox.Enabled          = $false
+$ServiceUserBox.DropDownStyle    = [System.Windows.Forms.ComboBoxStyle]::DropDownList
+$GUIElementsCollection += $ServiceUserBox
+
+$MigrateLibraryCheck                       = New-Object system.Windows.Forms.CheckBox
+$MigrateLibraryCheck.text                  = "Import Emby Library"
+$MigrateLibraryCheck.AutoSize              = $false
+$MigrateLibraryCheck.width                 = 160
+$MigrateLibraryCheck.height                = 20
+$MigrateLibraryCheck.location              = New-Object System.Drawing.Point(5,170)
+$MigrateLibraryCheck.Font                  = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $MigrateLibraryCheck
+
+$LibraryMigrationLabel            = New-Object system.Windows.Forms.Label
+$LibraryMigrationLabel.text       = "Emby Library Path"
+$LibraryMigrationLabel.TextAlign  = [System.Drawing.ContentAlignment]::MiddleLeft
+$LibraryMigrationLabel.AutoSize   = $false
+$LibraryMigrationLabel.width      = 120
+$LibraryMigrationLabel.height     = 20
+$LibraryMigrationLabel.location   = New-Object System.Drawing.Point(15,190)
+$LibraryMigrationLabel.Font       = 'Microsoft Sans Serif,10'
+$LibraryMigrationLabel.Visible    = $false
+$LibraryMigrationLabel.Enabled    = $false
+$GUIElementsCollection += $LibraryMigrationLabel
+
+$LibraryLocationBox              = New-Object system.Windows.Forms.TextBox
+$LibraryLocationBox.multiline    = $false
+$LibraryLocationBox.width        = 175
+$LibraryLocationBox.height       = 20
+$LibraryLocationBox.location     = New-Object System.Drawing.Point(140,190)
+$LibraryLocationBox.Text            = $Script:defaultEmbyDataDir
+$LibraryLocationBox.Font         = 'Microsoft Sans Serif,10'
+$LibraryLocationBox.Visible      = $false
+$LibraryLocationBox.Enabled      = $false
+$GUIElementsCollection += $LibraryLocationBox
+
+$CreateShortcutCheck                       = New-Object system.Windows.Forms.CheckBox
+$CreateShortcutCheck.text                  = "Desktop Shortcut"
+$CreateShortcutCheck.AutoSize              = $false
+$CreateShortcutCheck.width                 = 150
+$CreateShortcutCheck.height                = 20
+$CreateShortcutCheck.location              = New-Object System.Drawing.Point(5,215)
+$CreateShortcutCheck.Font                  = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $CreateShortcutCheck
+
+$StartProgramCheck                       = New-Object system.Windows.Forms.CheckBox
+$StartProgramCheck.text                  = "Start Jellyfin"
+$StartProgramCheck.AutoSize              = $false
+$StartProgramCheck.width                 = 160
+$StartProgramCheck.height                = 20
+$StartProgramCheck.location              = New-Object System.Drawing.Point(160,215)
+$StartProgramCheck.Font                  = 'Microsoft Sans Serif,10'
+$GUIElementsCollection += $StartProgramCheck
+
+$InstallForm.controls.AddRange($GUIElementsCollection)
+$InstallForm.Controls.Add($ProgressBar)
+
+#region gui events {
+$InstallButton.Add_Click({ InstallJellyfin })
+$CustomLibraryCheck.Add_CheckedChanged({CustomLibraryCheckChanged})
+$InstallAsServiceCheck.Add_CheckedChanged({ServiceBoxCheckChanged})
+$ServiceUserBox.Add_SelectedValueChanged({ UserSelect })
+$MigrateLibraryCheck.Add_CheckedChanged({MigrateLibraryCheckboxChanged})
+$CreateShortcutCheck.Add_CheckedChanged({CreateShortcutBoxCheckChanged})
+$StartProgramCheck.Add_CheckedChanged({StartJellyFinBoxCheckChanged})
+#endregion events }
+
+#endregion GUI }
+
+
+[void]$InstallForm.ShowDialog()

+ 1 - 0
install.bat

@@ -0,0 +1 @@
+powershell.exe -executionpolicy Bypass -file install-jellyfin.ps1

+ 22 - 0
new-file-header.txt

@@ -0,0 +1,22 @@
+### This header should be used to start new files.
+### It provides an explicit per-file license reference that should be present on all new files.
+### To use this header, delete these lines and the following empty line, modify <filename> to
+### the proper full path, and then add new code following the header and a single empty line.
+
+// <filename>
+// Part of the Jellyfin project (https://jellyfin.media)
+//
+//    All copyright belongs to the Jellyfin contributors; a full list can
+//    be found in the file CONTRIBUTORS.md
+//
+//    This program is free software: you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation, version 2.
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License
+//    along with this program.  If not, see <https://www.gnu.org/licenses/>.