Browse Source

expose Tmdb collection id in editor.

Luke Pulverenti 11 years ago
parent
commit
1f162e39b1
19 changed files with 271 additions and 193 deletions
  1. 1 3
      MediaBrowser.Api/MediaBrowser.Api.csproj
  2. 4 0
      MediaBrowser.Common.Implementations/BaseApplicationHost.cs
  3. 2 2
      MediaBrowser.Controller/Entities/Video.cs
  4. 73 67
      MediaBrowser.Providers/ImageFromMediaLocationProvider.cs
  5. 2 1
      MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
  6. 0 4
      MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
  7. 10 7
      MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
  8. 3 1
      MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs
  9. 4 1
      MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs
  10. 32 20
      MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
  11. 3 1
      MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs
  12. 3 1
      MediaBrowser.Server.Implementations/Persistence/SqliteNotificationsRepository.cs
  13. 3 1
      MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs
  14. 84 0
      MediaBrowser.Server.Implementations/Persistence/SqliteShrinkMemoryTimer.cs
  15. 3 1
      MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs
  16. 4 1
      MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs
  17. 0 80
      MediaBrowser.Server.Implementations/swagger-ui/index.html
  18. 38 0
      MediaBrowser.ServerApplication/EntryPoints/ResourceEntryPoint.cs
  19. 2 2
      MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj

+ 1 - 3
MediaBrowser.Api/MediaBrowser.Api.csproj

@@ -147,9 +147,7 @@
   <ItemGroup>
     <None Include="packages.config" />
   </ItemGroup>
-  <ItemGroup>
-    <Folder Include="Filters\" />
-  </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
     <PostBuildEvent>

+ 4 - 0
MediaBrowser.Common.Implementations/BaseApplicationHost.cs

@@ -16,6 +16,7 @@ using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Updates;
+using ServiceStack;
 using SimpleInjector;
 using System;
 using System.Collections.Generic;
@@ -181,6 +182,9 @@ namespace MediaBrowser.Common.Implementations
         /// <returns>Task.</returns>
         public virtual async Task Init()
         {
+            // https://github.com/ServiceStack/ServiceStack/blob/master/tests/ServiceStack.WebHost.IntegrationTests/Web.config#L4
+            Licensing.RegisterLicense("1001-e1JlZjoxMDAxLE5hbWU6VGVzdCBCdXNpbmVzcyxUeXBlOkJ1c2luZXNzLEhhc2g6UHVNTVRPclhvT2ZIbjQ5MG5LZE1mUTd5RUMzQnBucTFEbTE3TDczVEF4QUNMT1FhNXJMOWkzVjFGL2ZkVTE3Q2pDNENqTkQyUktRWmhvUVBhYTBiekJGUUZ3ZE5aZHFDYm9hL3lydGlwUHI5K1JsaTBYbzNsUC85cjVJNHE5QVhldDN6QkE4aTlvdldrdTgyTk1relY2eis2dFFqTThYN2lmc0JveHgycFdjPSxFeHBpcnk6MjAxMy0wMS0wMX0=");
+            
             JsonSerializer = CreateJsonSerializer();
 
             IsFirstRun = !ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted;

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

@@ -273,7 +273,7 @@ namespace MediaBrowser.Controller.Entities
             return base.GetDeletePaths();
         }
 
-        public IEnumerable<MediaStream> GetMediaStreams()
+        public virtual IEnumerable<MediaStream> GetMediaStreams()
         {
             return ItemRepository.GetMediaStreams(new MediaStreamQuery
             {
@@ -281,7 +281,7 @@ namespace MediaBrowser.Controller.Entities
             });
         }
 
-        public MediaStream GetDefaultVideoStream()
+        public virtual MediaStream GetDefaultVideoStream()
         {
             if (!DefaultVideoStreamIndex.HasValue)
             {

+ 73 - 67
MediaBrowser.Providers/ImageFromMediaLocationProvider.cs

@@ -23,7 +23,7 @@ namespace MediaBrowser.Providers
     public class ImageFromMediaLocationProvider : BaseMetadataProvider
     {
         protected readonly IFileSystem FileSystem;
-        
+
         public ImageFromMediaLocationProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
@@ -54,6 +54,7 @@ namespace MediaBrowser.Providers
 
                 return item.IsInMixedFolder && item.Parent != null && !(item is Episode);
             }
+
             return false;
         }
 
@@ -153,6 +154,13 @@ namespace MediaBrowser.Providers
                 .FirstOrDefault(i => i != null);
         }
 
+        protected virtual FileSystemInfo GetImage(List<FileSystemInfo> files, string filenameWithoutExtension)
+        {
+            return BaseItem.SupportedImageExtensions
+                .Select(i => files.FirstOrDefault(f => string.Equals(f.Extension, i, StringComparison.OrdinalIgnoreCase) && string.Equals(filenameWithoutExtension, Path.GetFileNameWithoutExtension(f.Name), StringComparison.OrdinalIgnoreCase)))
+                .FirstOrDefault(i => i != null);
+        }
+
         protected virtual string GetFullImagePath(BaseItem item, ItemResolveArgs args, string filenameWithoutExtension, string extension)
         {
             var path = item.MetaLocation;
@@ -258,24 +266,13 @@ namespace MediaBrowser.Providers
             var isFileSystemItem = item.LocationType == LocationType.FileSystem;
 
             // Support plex/xbmc convention
-            if (image == null && item is Season && item.IndexNumber.HasValue && isFileSystemItem)
+            if (image == null)
             {
-                var seasonMarker = item.IndexNumber.Value == 0
-                                       ? "-specials"
-                                       : item.IndexNumber.Value.ToString("00", _usCulture);
-
-                // Get this one directly from the file system since we have to go up a level
-                var filename = "season" + seasonMarker + "-poster";
-
-                var path = Path.GetDirectoryName(item.Path);
-
-                path = Path.Combine(path, filename);
-
-                image = new FileInfo(path);
-
-                if (!image.Exists)
+                // Supprt xbmc conventions
+                var season = item as Season;
+                if (season != null && item.IndexNumber.HasValue && isFileSystemItem)
                 {
-                    image = null;
+                    image = GetSeasonImageFromSeriesFolder(season, "-poster");
                 }
             }
 
@@ -315,26 +312,13 @@ namespace MediaBrowser.Providers
 
             if (image == null)
             {
+                var isFileSystemItem = item.LocationType == LocationType.FileSystem;
+
                 // Supprt xbmc conventions
-                if (item is Season && item.IndexNumber.HasValue && item.LocationType == LocationType.FileSystem)
+                var season = item as Season;
+                if (season != null && item.IndexNumber.HasValue && isFileSystemItem)
                 {
-                    var seasonMarker = item.IndexNumber.Value == 0
-                                           ? "-specials"
-                                           : item.IndexNumber.Value.ToString("00", _usCulture);
-
-                    // Get this one directly from the file system since we have to go up a level
-                    var filename = "season" + seasonMarker + "-banner";
-
-                    var path = Path.GetDirectoryName(item.Path);
-
-                    path = Path.Combine(path, filename);
-
-                    image = new FileInfo(path);
-
-                    if (!image.Exists)
-                    {
-                        image = null;
-                    }
+                    image = GetSeasonImageFromSeriesFolder(season, "-banner");
                 }
             }
 
@@ -356,26 +340,13 @@ namespace MediaBrowser.Providers
 
             if (image == null)
             {
+                var isFileSystemItem = item.LocationType == LocationType.FileSystem;
+
                 // Supprt xbmc conventions
-                if (item is Season && item.IndexNumber.HasValue && item.LocationType == LocationType.FileSystem)
+                var season = item as Season;
+                if (season != null && item.IndexNumber.HasValue && isFileSystemItem)
                 {
-                    var seasonMarker = item.IndexNumber.Value == 0
-                                           ? "-specials"
-                                           : item.IndexNumber.Value.ToString("00", _usCulture);
-
-                    // Get this one directly from the file system since we have to go up a level
-                    var filename = "season" + seasonMarker + "-landscape";
-
-                    var path = Path.GetDirectoryName(item.Path);
-
-                    path = Path.Combine(path, filename);
-
-                    image = new FileInfo(path);
-
-                    if (!image.Exists)
-                    {
-                        image = null;
-                    }
+                    image = GetSeasonImageFromSeriesFolder(season, "-landscape");
                 }
             }
 
@@ -420,22 +391,12 @@ namespace MediaBrowser.Providers
             PopulateBackdrops(item, args, backdropFiles, "background", "background-");
             PopulateBackdrops(item, args, backdropFiles, "art", "art-");
 
-            if (item is Season && item.IndexNumber.HasValue && isFileSystemItem)
+            var season = item as Season;
+            if (season != null && item.IndexNumber.HasValue && isFileSystemItem)
             {
-                var seasonMarker = item.IndexNumber.Value == 0
-                                       ? "-specials"
-                                       : item.IndexNumber.Value.ToString("00", _usCulture);
-
-                // Get this one directly from the file system since we have to go up a level
-                var filename = "season" + seasonMarker + "-fanart";
-
-                var path = Path.GetDirectoryName(item.Path);
+                var image = GetSeasonImageFromSeriesFolder(season, "-fanart");
 
-                path = Path.Combine(path, filename);
-
-                var image = new FileInfo(path);
-
-                if (image.Exists)
+                if (image != null)
                 {
                     backdropFiles.Add(image.FullName);
                 }
@@ -452,6 +413,51 @@ namespace MediaBrowser.Providers
             }
         }
 
+        private FileSystemInfo GetSeasonImageFromSeriesFolder(Season season, string imageSuffix)
+        {
+            var series = season.Series;
+            var seriesFolderArgs = series.ResolveArgs;
+
+            var seasonNumber = season.IndexNumber;
+
+            string filename = null;
+            FileSystemInfo image;
+
+            if (seasonNumber.HasValue)
+            {
+                var seasonMarker = seasonNumber.Value == 0
+                                       ? "-specials"
+                                       : seasonNumber.Value.ToString("00", _usCulture);
+
+                // Get this one directly from the file system since we have to go up a level
+                filename = "season" + seasonMarker + imageSuffix;
+
+                image = GetImage(series, seriesFolderArgs, filename);
+
+                if (image != null && image.Exists)
+                {
+                    return image;
+                }
+            }
+
+            var previousFilename = filename;
+
+            // Try using the season name
+            filename = season.Name.ToLower().Replace(" ", string.Empty) + imageSuffix;
+
+            if (!string.Equals(previousFilename, filename))
+            {
+                image = GetImage(series, seriesFolderArgs, filename);
+
+                if (image != null && image.Exists)
+                {
+                    return image;
+                }
+            }
+
+            return null;
+        }
+
         /// <summary>
         /// Populates the backdrops from extra fanart.
         /// </summary>

+ 2 - 1
MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs

@@ -74,7 +74,8 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
             try
             {
-                sizeDictionary = jsonSerializer.DeserializeFromFile<Dictionary<Guid, ImageSize>>(ImageSizeFile);
+                sizeDictionary = jsonSerializer.DeserializeFromFile<Dictionary<Guid, ImageSize>>(ImageSizeFile) ?? 
+                    new Dictionary<Guid, ImageSize>();
             }
             catch (FileNotFoundException)
             {

+ 0 - 4
MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs

@@ -5,7 +5,6 @@ using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Logging;
 using ServiceStack;
-using ServiceStack.Configuration;
 using ServiceStack.Host;
 using ServiceStack.Host.Handlers;
 using ServiceStack.Host.HttpListener;
@@ -58,9 +57,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
         public HttpListenerHost(IApplicationHost applicationHost, ILogManager logManager, string serviceName, string handlerPath, string defaultRedirectPath, params Assembly[] assembliesWithServices)
             : base(serviceName, assembliesWithServices)
         {
-            // https://github.com/ServiceStack/ServiceStack/blob/master/tests/ServiceStack.WebHost.IntegrationTests/Web.config#L4
-            Licensing.RegisterLicense("1001-e1JlZjoxMDAxLE5hbWU6VGVzdCBCdXNpbmVzcyxUeXBlOkJ1c2luZXNzLEhhc2g6UHVNTVRPclhvT2ZIbjQ5MG5LZE1mUTd5RUMzQnBucTFEbTE3TDczVEF4QUNMT1FhNXJMOWkzVjFGL2ZkVTE3Q2pDNENqTkQyUktRWmhvUVBhYTBiekJGUUZ3ZE5aZHFDYm9hL3lydGlwUHI5K1JsaTBYbzNsUC85cjVJNHE5QVhldDN6QkE4aTlvdldrdTgyTk1relY2eis2dFFqTThYN2lmc0JveHgycFdjPSxFeHBpcnk6MjAxMy0wMS0wMX0=");
-
             DefaultRedirectPath = defaultRedirectPath;
             ServerName = serviceName;
             HandlerPath = handlerPath;

+ 10 - 7
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -37,18 +37,23 @@
     <Reference Include="Alchemy">
       <HintPath>..\packages\Alchemy.2.2.1\lib\net40\Alchemy.dll</HintPath>
     </Reference>
-    <Reference Include="ServiceStack, Version=3.9.70.0, Culture=neutral, processorArchitecture=MSIL">
+    <Reference Include="ServiceStack, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\ThirdParty\ServiceStack\ServiceStack.dll</HintPath>
     </Reference>
-    <Reference Include="ServiceStack.Client">
+    <Reference Include="ServiceStack.Client, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
       <HintPath>..\ThirdParty\ServiceStack\ServiceStack.Client.dll</HintPath>
     </Reference>
-    <Reference Include="ServiceStack.Interfaces, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+    <Reference Include="ServiceStack.Common, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\ThirdParty\ServiceStack\ServiceStack.Common.dll</HintPath>
+    </Reference>
+    <Reference Include="ServiceStack.Interfaces, Version=4.0.0.0, Culture=neutral, PublicKeyToken=e06fbc6124f57c43, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll</HintPath>
     </Reference>
-    <Reference Include="ServiceStack.Text, Version=3.9.70.0, Culture=neutral, processorArchitecture=MSIL">
+    <Reference Include="ServiceStack.Text, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\ThirdParty\ServiceStack\ServiceStack.Text.dll</HintPath>
     </Reference>
@@ -143,6 +148,7 @@
     <Compile Include="Persistence\SqliteMediaStreamsRepository.cs" />
     <Compile Include="Persistence\SqliteNotificationsRepository.cs" />
     <Compile Include="Persistence\SqliteProviderInfoRepository.cs" />
+    <Compile Include="Persistence\SqliteShrinkMemoryTimer.cs" />
     <Compile Include="Persistence\TypeMapper.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Providers\ImageSaver.cs" />
@@ -237,9 +243,6 @@
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="Localization\Ratings\ca.txt" />
-    <Content Include="swagger-ui\index.html">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(SolutionDir)\.nuget\nuget.targets" />

+ 3 - 1
MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs

@@ -44,7 +44,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
                                 "create index if not exists idx_chapters on chapters(ItemId, ChapterIndex)",
 
                                 //pragmas
-                                "pragma temp_store = memory"
+                                "pragma temp_store = memory",
+
+                                "pragma shrink_memory"
                                };
 
             _connection.RunQueries(queries, _logger);

+ 4 - 1
MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs

@@ -86,8 +86,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
                                 "create table if not exists userdisplaypreferences (id GUID, userId GUID, client text, data BLOB)",
                                 "create unique index if not exists userdisplaypreferencesindex on userdisplaypreferences (id, userId, client)",
+
                                 //pragmas
-                                "pragma temp_store = memory"
+                                "pragma temp_store = memory",
+
+                                "pragma shrink_memory"
                                };
 
             _connection.RunQueries(queries, _logger);

+ 32 - 20
MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs

@@ -124,18 +124,24 @@ namespace MediaBrowser.Server.Implementations.Persistence
                                 "create index if not exists idx_ChildrenIds on ChildrenIds(ParentId,ItemId)",
 
                                 //pragmas
-                                "pragma temp_store = memory"
+                                "pragma temp_store = memory",
+
+                                "pragma shrink_memory"
                                };
 
             _connection.RunQueries(queries, _logger);
 
             PrepareStatements();
-            
+
             _mediaStreamsRepository.Initialize();
             _providerInfoRepository.Initialize();
             _chapterRepository.Initialize();
+
+            _shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
         }
 
+        private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
+
         /// <summary>
         /// The _write lock
         /// </summary>
@@ -402,6 +408,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 {
                     lock (_disposeLock)
                     {
+                        if (_shrinkMemoryTimer != null)
+                        {
+                            _shrinkMemoryTimer.Dispose();
+                            _shrinkMemoryTimer = null;
+                        }
+                        
                         if (_connection != null)
                         {
                             if (_connection.IsOpen())
@@ -412,30 +424,30 @@ namespace MediaBrowser.Server.Implementations.Persistence
                             _connection.Dispose();
                             _connection = null;
                         }
+
+                        if (_chapterRepository != null)
+                        {
+                            _chapterRepository.Dispose();
+                            _chapterRepository = null;
+                        }
+
+                        if (_mediaStreamsRepository != null)
+                        {
+                            _mediaStreamsRepository.Dispose();
+                            _mediaStreamsRepository = null;
+                        }
+
+                        if (_providerInfoRepository != null)
+                        {
+                            _providerInfoRepository.Dispose();
+                            _providerInfoRepository = null;
+                        }
                     }
                 }
                 catch (Exception ex)
                 {
                     _logger.ErrorException("Error disposing database", ex);
                 }
-
-                if (_chapterRepository != null)
-                {
-                    _chapterRepository.Dispose();
-                    _chapterRepository = null;
-                }
-
-                if (_mediaStreamsRepository != null)
-                {
-                    _mediaStreamsRepository.Dispose();
-                    _mediaStreamsRepository = null;
-                }
-
-                if (_providerInfoRepository != null)
-                {
-                    _providerInfoRepository.Dispose();
-                    _providerInfoRepository = null;
-                }
             }
         }
 

+ 3 - 1
MediaBrowser.Server.Implementations/Persistence/SqliteMediaStreamsRepository.cs

@@ -43,7 +43,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
                                 "create index if not exists idx_mediastreams on mediastreams(ItemId, StreamIndex)",
 
                                 //pragmas
-                                "pragma temp_store = memory"
+                                "pragma temp_store = memory",
+
+                                "pragma shrink_memory"
                                };
 
             _connection.RunQueries(queries, _logger);

+ 3 - 1
MediaBrowser.Server.Implementations/Persistence/SqliteNotificationsRepository.cs

@@ -45,7 +45,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
                                 "create index if not exists idx_Notifications on Notifications(Id, UserId)",
 
                                 //pragmas
-                                "pragma temp_store = memory"
+                                "pragma temp_store = memory",
+
+                                "pragma shrink_memory"
                                };
 
             _connection.RunQueries(queries, _logger);

+ 3 - 1
MediaBrowser.Server.Implementations/Persistence/SqliteProviderInfoRepository.cs

@@ -42,7 +42,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
                                 "create index if not exists idx_providerinfos on providerinfos(ItemId, ProviderId)",
 
                                 //pragmas
-                                "pragma temp_store = memory"
+                                "pragma temp_store = memory",
+
+                                "pragma shrink_memory"
                                };
 
             _connection.RunQueries(queries, _logger);

+ 84 - 0
MediaBrowser.Server.Implementations/Persistence/SqliteShrinkMemoryTimer.cs

@@ -0,0 +1,84 @@
+using MediaBrowser.Model.Logging;
+using System;
+using System.Data;
+using System.Threading;
+
+namespace MediaBrowser.Server.Implementations.Persistence
+{
+    class SqliteShrinkMemoryTimer : IDisposable
+    {
+        private Timer _shrinkMemoryTimer;
+
+        private readonly SemaphoreSlim _writeLock;
+        private readonly ILogger _logger;
+        private readonly IDbConnection _connection;
+
+        public SqliteShrinkMemoryTimer(IDbConnection connection, SemaphoreSlim writeLock, ILogger logger)
+        {
+            _connection = connection;
+            _writeLock = writeLock;
+            _logger = logger;
+
+            _shrinkMemoryTimer = new Timer(TimerCallback, null, TimeSpan.FromMinutes(30), TimeSpan.FromMinutes(30));
+        }
+
+        private async void TimerCallback(object state)
+        {
+            await _writeLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
+
+            IDbTransaction transaction = null;
+
+            try
+            {
+                transaction = _connection.BeginTransaction();
+
+                using (var cmd = _connection.CreateCommand())
+                {
+                    cmd.Transaction = transaction;
+                    cmd.CommandText = "pragma shrink_memory";
+                    cmd.ExecuteNonQuery();
+                }
+
+                transaction.Commit();
+            }
+            catch (OperationCanceledException)
+            {
+                if (transaction != null)
+                {
+                    transaction.Rollback();
+                }
+
+                throw;
+            }
+            catch (Exception e)
+            {
+                _logger.ErrorException("Failed to save items:", e);
+
+                if (transaction != null)
+                {
+                    transaction.Rollback();
+                }
+
+                throw;
+            }
+            finally
+            {
+                if (transaction != null)
+                {
+                    transaction.Dispose();
+                }
+
+                _writeLock.Release();
+            }
+        }
+
+        public void Dispose()
+        {
+            if (_shrinkMemoryTimer != null)
+            {
+                _shrinkMemoryTimer.Dispose();
+                _shrinkMemoryTimer = null;
+            }
+        }
+    }
+}

+ 3 - 1
MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs

@@ -72,7 +72,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
                                 "create unique index if not exists userdataindex on userdata (key, userId)",
 
                                 //pragmas
-                                "pragma temp_store = memory"
+                                "pragma temp_store = memory",
+
+                                "pragma shrink_memory"
                                };
 
             _connection.RunQueries(queries, _logger);

+ 4 - 1
MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs

@@ -77,8 +77,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
                                 "create table if not exists users (guid GUID primary key, data BLOB)",
                                 "create index if not exists idx_users on users(guid)",
                                 "create table if not exists schema_version (table_name primary key, version)",
+
                                 //pragmas
-                                "pragma temp_store = memory"
+                                "pragma temp_store = memory",
+
+                                "pragma shrink_memory"
                                };
 
             _connection.RunQueries(queries, _logger);

+ 0 - 80
MediaBrowser.Server.Implementations/swagger-ui/index.html

@@ -1,80 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <title>Swagger UI</title>
-    <link href='//fonts.googleapis.com/css?family=Droid+Sans:400,700' rel='stylesheet' type='text/css'/>
-    <link href='css/hightlight.default.css' media='screen' rel='stylesheet' type='text/css'/>
-    <link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
-    <script src='lib/jquery-1.8.0.min.js' type='text/javascript'></script>
-    <script src='lib/jquery.slideto.min.js' type='text/javascript'></script>
-    <script src='lib/jquery.wiggle.min.js' type='text/javascript'></script>
-    <script src='lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
-    <script src='lib/handlebars-1.0.rc.1.js' type='text/javascript'></script>
-    <script src='lib/underscore-min.js' type='text/javascript'></script>
-    <script src='lib/backbone-min.js' type='text/javascript'></script>
-    <script src='lib/swagger.js' type='text/javascript'></script>
-    <script src='swagger-ui.js' type='text/javascript'></script>
-    <script src='lib/highlight.7.3.pack.js' type='text/javascript'></script>
-
-    <script type="text/javascript">
-	$(function () {
-	    window.swaggerUi = new SwaggerUi({
-	        discoveryUrl: "../resources",
-	        apiKey: "special-key",
-                dom_id:"swagger-ui-container",
-                supportHeaderParams: false,
-                supportedSubmitMethods: ['get', 'post', 'put'],
-                onComplete: function(swaggerApi, swaggerUi){
-                	if(console) {
-                        console.log("Loaded SwaggerUI")
-                        console.log(swaggerApi);
-                        console.log(swaggerUi);
-                    }
-                  $('pre code').each(function(i, e) {hljs.highlightBlock(e)});
-                },
-                onFailure: function(data) {
-                	if(console) {
-                        console.log("Unable to Load SwaggerUI");
-                        console.log(data);
-                    }
-                },
-                docExpansion: "none"
-            });
-
-            window.swaggerUi.load();
-        });
-
-    </script>
-</head>
-
-<body>
-<div id='header'>
-    <div class="swagger-ui-wrap">
-        <a id="logo" href="http://swagger.wordnik.com">swagger</a>
-
-        <form id='api_selector'>
-            <div class='input icon-btn'>
-                <img id="show-pet-store-icon" src="images/pet_store_api.png" title="Show Swagger Petstore Example Apis">
-            </div>
-            <div class='input icon-btn'>
-                <img id="show-wordnik-dev-icon" src="images/wordnik_api.png" title="Show Wordnik Developer Apis">
-            </div>
-            <div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl"
-                                      type="text"/></div>
-            <div class='input'><input placeholder="api_key" id="input_apiKey" name="apiKey" type="text"/></div>
-            <div class='input'><a id="explore" href="#">Explore</a></div>
-        </form>
-    </div>
-</div>
-
-<div id="message-bar" class="swagger-ui-wrap">
-    &nbsp;
-</div>
-
-<div id="swagger-ui-container" class="swagger-ui-wrap">
-
-</div>
-
-</body>
-
-</html>

+ 38 - 0
MediaBrowser.ServerApplication/EntryPoints/ResourceEntryPoint.cs

@@ -0,0 +1,38 @@
+using MediaBrowser.Controller.Plugins;
+using System;
+using System.Threading;
+
+namespace MediaBrowser.ServerApplication.EntryPoints
+{
+    public class ResourceEntryPoint : IServerEntryPoint
+    {
+        private Timer _timer;
+
+        public void Run()
+        {
+            _timer = new Timer(TimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(30));
+        }
+
+        private void TimerCallback(object state)
+        {
+            try
+            {
+                // Bad practice, i know. But we keep a lot in memory, unfortunately.
+                GC.Collect(2, GCCollectionMode.Forced, true);
+                GC.Collect(2, GCCollectionMode.Forced, true);
+            }
+            catch
+            {
+            }
+        }
+
+        public void Dispose()
+        {
+            if (_timer != null)
+            {
+                _timer.Dispose();
+                _timer = null;
+            }
+        }
+    }
+}

+ 2 - 2
MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj

@@ -131,8 +131,7 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\packages\MediaBrowser.IsoMounting.3.0.65\lib\net45\pfmclrapi.dll</HintPath>
     </Reference>
-    <Reference Include="ServiceStack.Interfaces, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
+    <Reference Include="ServiceStack.Interfaces">
       <HintPath>..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll</HintPath>
     </Reference>
     <Reference Include="SimpleInjector, Version=2.3.6.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
@@ -161,6 +160,7 @@
     <Compile Include="BackgroundService.cs">
       <SubType>Component</SubType>
     </Compile>
+    <Compile Include="EntryPoints\ResourceEntryPoint.cs" />
     <Compile Include="EntryPoints\StartupWizard.cs" />
     <Compile Include="FFMpeg\FFMpegDownloadInfo.cs" />
     <Compile Include="FFMpeg\FFMpegInfo.cs" />