aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke <luke.pulverenti@gmail.com>2016-12-13 13:27:53 -0500
committerGitHub <noreply@github.com>2016-12-13 13:27:53 -0500
commit6cdbb25b9d756b58806414455cc4c4d1bc555217 (patch)
treeb6bc4f10ad1c6f758215a719b2be932b5979e896
parentb33dcdf7bd61a8096928e1b2b5e34af1c8373096 (diff)
parentffad9c27e4844eeab235f88cb45739370d22a83a (diff)
Merge pull request #2340 from MediaBrowser/dev
Dev
-rw-r--r--Emby.Common.Implementations/Networking/NetworkManager.cs23
-rw-r--r--Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs1
-rw-r--r--Emby.Dlna/Didl/DidlBuilder.cs6
-rw-r--r--Emby.Dlna/PlayTo/PlayToController.cs3
-rw-r--r--Emby.Server.Core/ApplicationHost.cs1
-rw-r--r--Emby.Server.Implementations/Activity/ActivityRepository.cs17
-rw-r--r--Emby.Server.Implementations/Data/BaseSqliteRepository.cs178
-rw-r--r--Emby.Server.Implementations/Data/SqliteExtensions.cs2
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs309
-rw-r--r--Emby.Server.Implementations/Data/SqliteUserDataRepository.cs30
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs105
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj2
-rw-r--r--Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs6
-rw-r--r--Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs3
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs58
-rw-r--r--Emby.Server.Implementations/Library/UserDataManager.cs7
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs22
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs6
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs1
-rw-r--r--Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs20
-rw-r--r--Emby.Server.Implementations/Security/AuthenticationRepository.cs14
-rw-r--r--Emby.Server.Implementations/TV/TVSeriesManager.cs2
-rw-r--r--MediaBrowser.Api/BaseApiService.cs32
-rw-r--r--MediaBrowser.Api/ItemLookupService.cs15
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs6
-rw-r--r--MediaBrowser.Api/Playback/StreamState.cs12
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs3
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs68
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs36
-rw-r--r--MediaBrowser.Controller/Entities/IHasUserData.cs6
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs2
-rw-r--r--MediaBrowser.Controller/Library/IUserDataManager.cs6
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs12
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs3
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs4
-rw-r--r--MediaBrowser.Model/Dlna/ConditionProcessor.cs26
-rw-r--r--MediaBrowser.Model/Dlna/ContainerProfile.cs8
-rw-r--r--MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs6
-rw-r--r--MediaBrowser.Model/Dlna/DeviceProfile.cs5
-rw-r--r--MediaBrowser.Model/Dlna/ProfileConditionValue.cs3
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs21
-rw-r--r--MediaBrowser.Model/Dlna/StreamInfo.cs12
-rw-r--r--MediaBrowser.Model/Querying/ItemFields.cs2
-rw-r--r--MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj4
-rw-r--r--MediaBrowser.Server.Startup.Common/Persistence/SqliteExtensions.cs57
-rw-r--r--RSSDP/SsdpDevicePublisherBase.cs8
-rw-r--r--src/Emby.Server/Emby.Server.xproj5
-rw-r--r--src/Emby.Server/project.json24
48 files changed, 736 insertions, 466 deletions
diff --git a/Emby.Common.Implementations/Networking/NetworkManager.cs b/Emby.Common.Implementations/Networking/NetworkManager.cs
index b9100f9db3..a4e6d47d40 100644
--- a/Emby.Common.Implementations/Networking/NetworkManager.cs
+++ b/Emby.Common.Implementations/Networking/NetworkManager.cs
@@ -198,6 +198,12 @@ namespace Emby.Common.Implementations.Networking
return Dns.GetHostAddressesAsync(hostName);
}
+ private readonly List<NetworkInterfaceType> _validNetworkInterfaceTypes = new List<NetworkInterfaceType>
+ {
+ NetworkInterfaceType.Ethernet,
+ NetworkInterfaceType.Wireless80211
+ };
+
private List<IPAddress> GetIPsDefault()
{
NetworkInterface[] interfaces;
@@ -223,9 +229,22 @@ namespace Emby.Common.Implementations.Networking
{
Logger.Debug("Querying interface: {0}. Type: {1}. Status: {2}", network.Name, network.NetworkInterfaceType, network.OperationalStatus);
- var properties = network.GetIPProperties();
+ var ipProperties = network.GetIPProperties();
+
+ // Try to exclude virtual adapters
+ // http://stackoverflow.com/questions/8089685/c-sharp-finding-my-machines-local-ip-address-and-not-the-vms
+ var addr = ipProperties.GatewayAddresses.FirstOrDefault();
+ if (addr == null|| string.Equals(addr.Address.ToString(), "0.0.0.0", StringComparison.OrdinalIgnoreCase))
+ {
+ return new List<IPAddress>();
+ }
+
+ //if (!_validNetworkInterfaceTypes.Contains(network.NetworkInterfaceType))
+ //{
+ // return new List<IPAddress>();
+ //}
- return properties.UnicastAddresses
+ return ipProperties.UnicastAddresses
.Where(i => i.IsDnsEligible)
.Select(i => i.Address)
.Where(i => i.AddressFamily == AddressFamily.InterNetwork)
diff --git a/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index f288c5c0f4..cbc7c7c2d8 100644
--- a/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -387,6 +387,7 @@ namespace Emby.Common.Implementations.ScheduledTasks
finally
{
_currentTask = null;
+ GC.Collect();
}
}
diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs
index 3dcdaf2efc..e968509b5e 100644
--- a/Emby.Dlna/Didl/DidlBuilder.cs
+++ b/Emby.Dlna/Didl/DidlBuilder.cs
@@ -207,7 +207,8 @@ namespace Emby.Dlna.Didl
streamInfo.TargetVideoStreamCount,
streamInfo.TargetAudioStreamCount,
streamInfo.TargetVideoCodecTag,
- streamInfo.IsTargetAVC);
+ streamInfo.IsTargetAVC,
+ streamInfo.AllAudioCodecs);
foreach (var contentFeature in contentFeatureList)
{
@@ -347,7 +348,8 @@ namespace Emby.Dlna.Didl
streamInfo.TargetVideoStreamCount,
streamInfo.TargetAudioStreamCount,
streamInfo.TargetVideoCodecTag,
- streamInfo.IsTargetAVC);
+ streamInfo.IsTargetAVC,
+ streamInfo.AllAudioCodecs);
var filename = url.Substring(0, url.IndexOf('?'));
diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs
index 7dff8bda13..bfc29d0f5f 100644
--- a/Emby.Dlna/PlayTo/PlayToController.cs
+++ b/Emby.Dlna/PlayTo/PlayToController.cs
@@ -541,7 +541,8 @@ namespace Emby.Dlna.PlayTo
streamInfo.TargetVideoStreamCount,
streamInfo.TargetAudioStreamCount,
streamInfo.TargetVideoCodecTag,
- streamInfo.IsTargetAVC);
+ streamInfo.IsTargetAVC,
+ streamInfo.AllAudioCodecs);
return list.FirstOrDefault();
}
diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs
index a6d2d32c0b..3b3313169d 100644
--- a/Emby.Server.Core/ApplicationHost.cs
+++ b/Emby.Server.Core/ApplicationHost.cs
@@ -489,6 +489,7 @@ namespace Emby.Server.Core
{
var migrations = new List<IVersionMigration>
{
+ new LibraryScanMigration(ServerConfigurationManager, TaskManager)
};
foreach (var task in migrations)
diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs
index 7ac0e680ca..bf88358465 100644
--- a/Emby.Server.Implementations/Activity/ActivityRepository.cs
+++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs
@@ -84,9 +84,6 @@ namespace Emby.Server.Implementations.Activity
{
using (var connection = CreateConnection(true))
{
- var list = new List<ActivityLogEntry>();
- var result = new QueryResult<ActivityLogEntry>();
-
var commandText = BaseActivitySelectText;
var whereClauses = new List<string>();
@@ -127,9 +124,12 @@ namespace Emby.Server.Implementations.Activity
statementTexts.Add(commandText);
statementTexts.Add("select count (Id) from ActivityLogEntries" + whereTextWithoutPaging);
- connection.RunInTransaction(db =>
+ return connection.RunInTransaction(db =>
{
- var statements = PrepareAllSafe(db, string.Join(";", statementTexts.ToArray())).ToList();
+ var list = new List<ActivityLogEntry>();
+ var result = new QueryResult<ActivityLogEntry>();
+
+ var statements = PrepareAllSafe(db, statementTexts).ToList();
using (var statement = statements[0])
{
@@ -153,10 +153,11 @@ namespace Emby.Server.Implementations.Activity
result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First();
}
- }, ReadTransactionMode);
- result.Items = list.ToArray();
- return result;
+ result.Items = list.ToArray();
+ return result;
+
+ }, ReadTransactionMode);
}
}
}
diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
index 9e60a43aab..206422176b 100644
--- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
+++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Logging;
@@ -25,7 +26,7 @@ namespace Emby.Server.Implementations.Data
protected TransactionMode TransactionMode
{
- get { return TransactionMode.Immediate; }
+ get { return TransactionMode.Deferred; }
}
protected TransactionMode ReadTransactionMode
@@ -43,6 +44,8 @@ namespace Emby.Server.Implementations.Data
//CheckOk(rc);
rc = raw.sqlite3_config(raw.SQLITE_CONFIG_MULTITHREAD, 1);
+ //rc = raw.sqlite3_config(raw.SQLITE_CONFIG_SINGLETHREAD, 1);
+ //rc = raw.sqlite3_config(raw.SQLITE_CONFIG_SERIALIZED, 1);
//CheckOk(rc);
rc = raw.sqlite3_enable_shared_cache(1);
@@ -53,84 +56,125 @@ namespace Emby.Server.Implementations.Data
private static bool _versionLogged;
private string _defaultWal;
+ protected ManagedConnection _connection;
- protected SQLiteDatabaseConnection CreateConnection(bool isReadOnly = false)
+ protected virtual bool EnableSingleConnection
{
- if (!_versionLogged)
- {
- _versionLogged = true;
- Logger.Info("Sqlite version: " + SQLite3.Version);
- Logger.Info("Sqlite compiler options: " + string.Join(",", SQLite3.CompilerOptions.ToArray()));
- }
-
- ConnectionFlags connectionFlags;
+ get { return true; }
+ }
- if (isReadOnly)
+ protected ManagedConnection CreateConnection(bool isReadOnly = false)
+ {
+ if (_connection != null)
{
- //Logger.Info("Opening read connection");
- //connectionFlags = ConnectionFlags.ReadOnly;
- connectionFlags = ConnectionFlags.Create;
- connectionFlags |= ConnectionFlags.ReadWrite;
+ return _connection;
}
- else
+
+ lock (WriteLock)
{
- //Logger.Info("Opening write connection");
- connectionFlags = ConnectionFlags.Create;
- connectionFlags |= ConnectionFlags.ReadWrite;
- }
+ if (!_versionLogged)
+ {
+ _versionLogged = true;
+ Logger.Info("Sqlite version: " + SQLite3.Version);
+ Logger.Info("Sqlite compiler options: " + string.Join(",", SQLite3.CompilerOptions.ToArray()));
+ }
- connectionFlags |= ConnectionFlags.SharedCached;
- connectionFlags |= ConnectionFlags.NoMutex;
+ ConnectionFlags connectionFlags;
- var db = SQLite3.Open(DbFilePath, connectionFlags, null);
+ if (isReadOnly)
+ {
+ //Logger.Info("Opening read connection");
+ //connectionFlags = ConnectionFlags.ReadOnly;
+ connectionFlags = ConnectionFlags.Create;
+ connectionFlags |= ConnectionFlags.ReadWrite;
+ }
+ else
+ {
+ //Logger.Info("Opening write connection");
+ connectionFlags = ConnectionFlags.Create;
+ connectionFlags |= ConnectionFlags.ReadWrite;
+ }
- if (string.IsNullOrWhiteSpace(_defaultWal))
- {
- _defaultWal = db.Query("PRAGMA journal_mode").SelectScalarString().First();
+ if (EnableSingleConnection)
+ {
+ connectionFlags |= ConnectionFlags.PrivateCache;
+ }
+ else
+ {
+ connectionFlags |= ConnectionFlags.SharedCached;
+ }
- Logger.Info("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal);
- }
+ connectionFlags |= ConnectionFlags.NoMutex;
- var queries = new List<string>
- {
- //"PRAGMA cache size=-10000"
- };
+ var db = SQLite3.Open(DbFilePath, connectionFlags, null);
- if (EnableTempStoreMemory)
- {
- queries.Add("PRAGMA temp_store = memory");
- }
+ if (string.IsNullOrWhiteSpace(_defaultWal))
+ {
+ _defaultWal = db.Query("PRAGMA journal_mode").SelectScalarString().First();
- //var cacheSize = CacheSize;
- //if (cacheSize.HasValue)
- //{
+ Logger.Info("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal);
+ }
- //}
+ var queries = new List<string>
+ {
+ //"PRAGMA cache size=-10000"
+ //"PRAGMA read_uncommitted = true",
+ "PRAGMA synchronous=Normal"
+ };
- ////foreach (var query in queries)
- ////{
- //// db.Execute(query);
- ////}
+ if (CacheSize.HasValue)
+ {
+ queries.Add("PRAGMA cache_size=-" + CacheSize.Value.ToString(CultureInfo.InvariantCulture));
+ }
- //Logger.Info("synchronous: " + db.Query("PRAGMA synchronous").SelectScalarString().First());
- //Logger.Info("temp_store: " + db.Query("PRAGMA temp_store").SelectScalarString().First());
+ if (EnableTempStoreMemory)
+ {
+ queries.Add("PRAGMA temp_store = memory");
+ }
- /*if (!string.Equals(_defaultWal, "wal", StringComparison.OrdinalIgnoreCase))
- {
- queries.Add("PRAGMA journal_mode=WAL");
+ //var cacheSize = CacheSize;
+ //if (cacheSize.HasValue)
+ //{
- using (WriteLock.Write())
+ //}
+
+ ////foreach (var query in queries)
+ ////{
+ //// db.Execute(query);
+ ////}
+
+ //Logger.Info("synchronous: " + db.Query("PRAGMA synchronous").SelectScalarString().First());
+ //Logger.Info("temp_store: " + db.Query("PRAGMA temp_store").SelectScalarString().First());
+
+ /*if (!string.Equals(_defaultWal, "wal", StringComparison.OrdinalIgnoreCase))
{
- db.ExecuteAll(string.Join(";", queries.ToArray()));
+ queries.Add("PRAGMA journal_mode=WAL");
+
+ using (WriteLock.Write())
+ {
+ db.ExecuteAll(string.Join(";", queries.ToArray()));
+ }
}
+ else*/
+ foreach (var query in queries)
+ {
+ db.Execute(query);
+ }
+
+ _connection = new ManagedConnection(db, false);
+
+ return _connection;
}
- else*/
- if (queries.Count > 0)
- {
- db.ExecuteAll(string.Join(";", queries.ToArray()));
- }
+ }
+
+ public IStatement PrepareStatement(ManagedConnection connection, string sql)
+ {
+ return connection.PrepareStatement(sql);
+ }
- return db;
+ public IStatement PrepareStatementSafe(ManagedConnection connection, string sql)
+ {
+ return connection.PrepareStatement(sql);
}
public IStatement PrepareStatement(IDatabaseConnection connection, string sql)
@@ -143,22 +187,23 @@ namespace Emby.Server.Implementations.Data
return connection.PrepareStatement(sql);
}
- public List<IStatement> PrepareAll(IDatabaseConnection connection, string sql)
+ public List<IStatement> PrepareAll(IDatabaseConnection connection, IEnumerable<string> sql)
{
- return connection.PrepareAll(sql).ToList();
+ return PrepareAllSafe(connection, sql);
}
- public List<IStatement> PrepareAllSafe(IDatabaseConnection connection, string sql)
+ public List<IStatement> PrepareAllSafe(IDatabaseConnection connection, IEnumerable<string> sql)
{
- return connection.PrepareAll(sql).ToList();
+ return sql.Select(connection.PrepareStatement).ToList();
}
- protected void RunDefaultInitialization(IDatabaseConnection db)
+ protected void RunDefaultInitialization(ManagedConnection db)
{
var queries = new List<string>
{
"PRAGMA journal_mode=WAL",
"PRAGMA page_size=4096",
+ "PRAGMA synchronous=Normal"
};
if (EnableTempStoreMemory)
@@ -171,6 +216,7 @@ namespace Emby.Server.Implementations.Data
}
db.ExecuteAll(string.Join(";", queries.ToArray()));
+ Logger.Info("PRAGMA synchronous=" + db.Query("PRAGMA synchronous").SelectScalarString().First());
}
protected virtual bool EnableTempStoreMemory
@@ -238,6 +284,12 @@ namespace Emby.Server.Implementations.Data
{
using (WriteLock.Write())
{
+ if (_connection != null)
+ {
+ _connection.Close();
+ _connection = null;
+ }
+
CloseConnection();
}
}
@@ -332,7 +384,7 @@ namespace Emby.Server.Implementations.Data
//{
// return new DummyToken();
//}
- return new ReadLockToken(obj);
+ return new WriteLockToken(obj);
}
public static IDisposable Write(this ReaderWriterLockSlim obj)
{
diff --git a/Emby.Server.Implementations/Data/SqliteExtensions.cs b/Emby.Server.Implementations/Data/SqliteExtensions.cs
index 5b25490872..d6ad0ba8ab 100644
--- a/Emby.Server.Implementations/Data/SqliteExtensions.cs
+++ b/Emby.Server.Implementations/Data/SqliteExtensions.cs
@@ -129,7 +129,7 @@ namespace Emby.Server.Implementations.Data
}
}
- public static void Attach(IDatabaseConnection db, string path, string alias)
+ public static void Attach(ManagedConnection db, string path, string alias)
{
var commandText = string.Format("attach @path as {0};", alias);
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 14b81022dd..5f2a314f9f 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -105,13 +105,7 @@ namespace Emby.Server.Implementations.Data
{
get
{
- var cacheSize = _config.Configuration.SqliteCacheSize;
- if (cacheSize <= 0)
- {
- cacheSize = Math.Min(Environment.ProcessorCount * 50000, 100000);
- }
-
- return 0 - cacheSize;
+ return 20000;
}
}
@@ -328,6 +322,8 @@ namespace Emby.Server.Implementations.Data
"drop table if exists Images",
"drop index if exists idx_Images",
"drop index if exists idx_TypeSeriesPresentationUniqueKey",
+ "drop index if exists idx_SeriesPresentationUniqueKey",
+ "drop index if exists idx_TypeSeriesPresentationUniqueKey2",
"create index if not exists idx_PathTypedBaseItems on TypedBaseItems(Path)",
"create index if not exists idx_ParentIdTypedBaseItems on TypedBaseItems(ParentId)",
@@ -343,8 +339,9 @@ namespace Emby.Server.Implementations.Data
// series
"create index if not exists idx_TypeSeriesPresentationUniqueKey1 on TypedBaseItems(Type,SeriesPresentationUniqueKey,PresentationUniqueKey,SortName)",
- // series next up
- "create index if not exists idx_SeriesPresentationUniqueKey on TypedBaseItems(SeriesPresentationUniqueKey)",
+ // series counts
+ // seriesdateplayed sort order
+ "create index if not exists idx_TypeSeriesPresentationUniqueKey3 on TypedBaseItems(SeriesPresentationUniqueKey,Type,IsFolder,IsVirtualItem)",
// live tv programs
"create index if not exists idx_TypeTopParentIdStartDate on TypedBaseItems(Type,TopParentId,StartDate)",
@@ -373,9 +370,9 @@ namespace Emby.Server.Implementations.Data
//await Vacuum(_connection).ConfigureAwait(false);
}
- userDataRepo.Initialize(WriteLock);
+ userDataRepo.Initialize(WriteLock, _connection);
- _shrinkMemoryTimer = _timerFactory.Create(OnShrinkMemoryTimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(30));
+ _shrinkMemoryTimer = _timerFactory.Create(OnShrinkMemoryTimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(15));
}
private void OnShrinkMemoryTimerCallback(object state)
@@ -698,12 +695,12 @@ namespace Emby.Server.Implementations.Data
{
var requiresReset = false;
- var statements = PrepareAll(db, string.Join(";", new string[]
+ var statements = PrepareAllSafe(db, new string[]
{
GetSaveItemCommandText(),
"delete from AncestorIds where ItemId=@ItemId",
"insert into AncestorIds (ItemId, AncestorId, AncestorIdText) values (@ItemId, @AncestorId, @AncestorIdText)"
- })).ToList();
+ }).ToList();
using (var saveItemStatement = statements[0])
{
@@ -1264,9 +1261,10 @@ namespace Emby.Server.Implementations.Data
return GetItem(row);
}
}
+
+ return null;
}
}
- return null;
}
private BaseItem GetItem(IReadOnlyList<IResultSetValue> reader)
@@ -2079,12 +2077,12 @@ namespace Emby.Server.Implementations.Data
throw new ArgumentNullException("id");
}
- var list = new List<ChapterInfo>();
-
using (WriteLock.Read())
{
using (var connection = CreateConnection(true))
{
+ var list = new List<ChapterInfo>();
+
using (var statement = PrepareStatementSafe(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc"))
{
statement.TryBind("@ItemId", id);
@@ -2094,10 +2092,10 @@ namespace Emby.Server.Implementations.Data
list.Add(GetChapter(row));
}
}
+
+ return list;
}
}
-
- return list;
}
/// <summary>
@@ -2240,7 +2238,7 @@ namespace Emby.Server.Implementations.Data
if (query.SimilarTo != null && query.User != null)
{
- return true;
+ //return true;
}
var sortingFields = query.SortBy.ToList();
@@ -2369,15 +2367,10 @@ namespace Emby.Server.Implementations.Data
builder.Append("+(Select Case When Abs(COALESCE(ProductionYear, 0) - @ItemProductionYear) < 10 Then 2 Else 0 End )");
builder.Append("+(Select Case When Abs(COALESCE(ProductionYear, 0) - @ItemProductionYear) < 5 Then 2 Else 0 End )");
- //// genres
- builder.Append("+ ((Select count(CleanValue) from ItemValues where ItemId=Guid and Type=2 and CleanValue in (select CleanValue from itemvalues where ItemId=@SimilarItemId and type=2)) * 10)");
-
- //// tags
- builder.Append("+ ((Select count(CleanValue) from ItemValues where ItemId=Guid and Type=4 and CleanValue in (select CleanValue from itemvalues where ItemId=@SimilarItemId and type=4)) * 10)");
-
- builder.Append("+ ((Select count(CleanValue) from ItemValues where ItemId=Guid and Type=5 and CleanValue in (select CleanValue from itemvalues where ItemId=@SimilarItemId and type=5)) * 10)");
+ //// genres, tags
+ builder.Append("+ ((Select count(CleanValue) from ItemValues where ItemId=Guid and Type in (2,3,4,5) and CleanValue in (select CleanValue from itemvalues where ItemId=@SimilarItemId and Type in (2,3,4,5))) * 10)");
- builder.Append("+ ((Select count(CleanValue) from ItemValues where ItemId=Guid and Type=3 and CleanValue in (select CleanValue from itemvalues where ItemId=@SimilarItemId and type=3)) * 3)");
+ //builder.Append("+ ((Select count(CleanValue) from ItemValues where ItemId=Guid and Type=3 and CleanValue in (select CleanValue from itemvalues where ItemId=@SimilarItemId and type=3)) * 3)");
//builder.Append("+ ((Select count(Name) from People where ItemId=Guid and Name in (select Name from People where ItemId=@SimilarItemId)) * 3)");
@@ -2475,8 +2468,6 @@ namespace Emby.Server.Implementations.Data
//commandText += GetGroupBy(query);
- int count = 0;
-
using (WriteLock.Read())
{
using (var connection = CreateConnection(true))
@@ -2493,14 +2484,13 @@ namespace Emby.Server.Implementations.Data
// Running this again will bind the params
GetWhereClauses(query, statement);
- count = statement.ExecuteQuery().SelectScalarInt().First();
+ var count = statement.ExecuteQuery().SelectScalarInt().First();
+ LogQueryTime("GetCount", commandText, now);
+ return count;
}
}
- LogQueryTime("GetCount", commandText, now);
}
-
- return count;
}
public List<BaseItem> GetItemList(InternalItemsQuery query)
@@ -2516,8 +2506,6 @@ namespace Emby.Server.Implementations.Data
var now = DateTime.UtcNow;
- var list = new List<BaseItem>();
-
// Hack for right now since we currently don't support filtering out these duplicates within a query
if (query.Limit.HasValue && query.EnableGroupByMetadataKey)
{
@@ -2558,53 +2546,59 @@ namespace Emby.Server.Implementations.Data
{
using (var connection = CreateConnection(true))
{
- using (var statement = PrepareStatementSafe(connection, commandText))
+ return connection.RunInTransaction(db =>
{
- if (EnableJoinUserData(query))
+ var list = new List<BaseItem>();
+
+ using (var statement = PrepareStatementSafe(db, commandText))
{
- statement.TryBind("@UserId", query.User.Id);
- }
+ if (EnableJoinUserData(query))
+ {
+ statement.TryBind("@UserId", query.User.Id);
+ }
- BindSimilarParams(query, statement);
+ BindSimilarParams(query, statement);
- // Running this again will bind the params
- GetWhereClauses(query, statement);
+ // Running this again will bind the params
+ GetWhereClauses(query, statement);
- foreach (var row in statement.ExecuteQuery())
- {
- var item = GetItem(row, query);
- if (item != null)
+ foreach (var row in statement.ExecuteQuery())
{
- list.Add(item);
+ var item = GetItem(row, query);
+ if (item != null)
+ {
+ list.Add(item);
+ }
}
}
- }
- }
- LogQueryTime("GetItemList", commandText, now);
- }
+ // Hack for right now since we currently don't support filtering out these duplicates within a query
+ if (query.EnableGroupByMetadataKey)
+ {
+ var limit = query.Limit ?? int.MaxValue;
+ limit -= 4;
+ var newList = new List<BaseItem>();
- // Hack for right now since we currently don't support filtering out these duplicates within a query
- if (query.EnableGroupByMetadataKey)
- {
- var limit = query.Limit ?? int.MaxValue;
- limit -= 4;
- var newList = new List<BaseItem>();
+ foreach (var item in list)
+ {
+ AddItem(newList, item);
- foreach (var item in list)
- {
- AddItem(newList, item);
+ if (newList.Count >= limit)
+ {
+ break;
+ }
+ }
- if (newList.Count >= limit)
- {
- break;
- }
- }
+ list = newList;
+ }
- list = newList;
- }
+ LogQueryTime("GetItemList", commandText, now);
- return list;
+ return list;
+
+ }, ReadTransactionMode);
+ }
+ }
}
private void AddItem(List<BaseItem> items, BaseItem newItem)
@@ -2642,7 +2636,7 @@ namespace Emby.Server.Implementations.Data
var slowThreshold = 1000;
#if DEBUG
- slowThreshold = 50;
+ slowThreshold = 2;
#endif
if (elapsed >= slowThreshold)
@@ -2723,7 +2717,6 @@ namespace Emby.Server.Implementations.Data
}
}
- var result = new QueryResult<BaseItem>();
var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0;
var statementTexts = new List<string>();
@@ -2753,9 +2746,10 @@ namespace Emby.Server.Implementations.Data
{
using (var connection = CreateConnection(true))
{
- connection.RunInTransaction(db =>
+ return connection.RunInTransaction(db =>
{
- var statements = PrepareAllSafe(db, string.Join(";", statementTexts.ToArray()))
+ var result = new QueryResult<BaseItem>();
+ var statements = PrepareAllSafe(db, statementTexts)
.ToList();
if (!isReturningZeroItems)
@@ -2801,12 +2795,12 @@ namespace Emby.Server.Implementations.Data
}
}
- }, ReadTransactionMode);
+ LogQueryTime("GetItems", commandText, now);
- LogQueryTime("GetItems", commandText, now);
+ result.Items = list.ToArray();
+ return result;
- result.Items = list.ToArray();
- return result;
+ }, ReadTransactionMode);
}
}
}
@@ -2967,12 +2961,12 @@ namespace Emby.Server.Implementations.Data
}
}
- var list = new List<Guid>();
-
using (WriteLock.Read())
{
using (var connection = CreateConnection(true))
{
+ var list = new List<Guid>();
+
using (var statement = PrepareStatementSafe(connection, commandText))
{
if (EnableJoinUserData(query))
@@ -2990,11 +2984,11 @@ namespace Emby.Server.Implementations.Data
list.Add(row[0].ReadGuid());
}
}
- }
- LogQueryTime("GetItemList", commandText, now);
+ LogQueryTime("GetItemList", commandText, now);
- return list;
+ return list;
+ }
}
}
@@ -3158,11 +3152,11 @@ namespace Emby.Server.Implementations.Data
{
using (var connection = CreateConnection(true))
{
- var result = new QueryResult<Guid>();
-
- connection.RunInTransaction(db =>
+ return connection.RunInTransaction(db =>
{
- var statements = PrepareAllSafe(db, string.Join(";", statementTexts.ToArray()))
+ var result = new QueryResult<Guid>();
+
+ var statements = PrepareAllSafe(db, statementTexts)
.ToList();
if (!isReturningZeroItems)
@@ -3204,12 +3198,12 @@ namespace Emby.Server.Implementations.Data
}
}
- }, ReadTransactionMode);
+ LogQueryTime("GetItemIds", commandText, now);
- LogQueryTime("GetItemIds", commandText, now);
+ result.Items = list.ToArray();
+ return result;
- result.Items = list.ToArray();
- return result;
+ }, ReadTransactionMode);
}
}
}
@@ -4658,26 +4652,23 @@ namespace Emby.Server.Implementations.Data
commandText += " order by ListOrder";
- var list = new List<string>();
using (WriteLock.Read())
{
using (var connection = CreateConnection(true))
{
- connection.RunInTransaction(db =>
+ var list = new List<string>();
+ using (var statement = PrepareStatementSafe(connection, commandText))
{
- using (var statement = PrepareStatementSafe(db, commandText))
- {
- // Run this again to bind the params
- GetPeopleWhereClauses(query, statement);
+ // Run this again to bind the params
+ GetPeopleWhereClauses(query, statement);
- foreach (var row in statement.ExecuteQuery())
- {
- list.Add(row.GetString(0));
- }
+ foreach (var row in statement.ExecuteQuery())
+ {
+ list.Add(row.GetString(0));
}
- }, ReadTransactionMode);
+ }
+ return list;
}
- return list;
}
}
@@ -4701,29 +4692,26 @@ namespace Emby.Server.Implementations.Data
commandText += " order by ListOrder";
- var list = new List<PersonInfo>();
-
using (WriteLock.Read())
{
using (var connection = CreateConnection(true))
{
- connection.RunInTransaction(db =>
+ var list = new List<PersonInfo>();
+
+ using (var statement = PrepareStatementSafe(connection, commandText))
{
- using (var statement = PrepareStatementSafe(db, commandText))
- {
- // Run this again to bind the params
- GetPeopleWhereClauses(query, statement);
+ // Run this again to bind the params
+ GetPeopleWhereClauses(query, statement);
- foreach (var row in statement.ExecuteQuery())
- {
- list.Add(GetPerson(row));
- }
+ foreach (var row in statement.ExecuteQuery())
+ {
+ list.Add(GetPerson(row));
}
- }, ReadTransactionMode);
+ }
+
+ return list;
}
}
-
- return list;
}
private List<string> GetPeopleWhereClauses(InternalPeopleQuery query, IStatement statement)
@@ -4904,8 +4892,6 @@ namespace Emby.Server.Implementations.Data
("Type=" + itemValueTypes[0].ToString(CultureInfo.InvariantCulture)) :
("Type in (" + string.Join(",", itemValueTypes.Select(i => i.ToString(CultureInfo.InvariantCulture)).ToArray()) + ")");
- var list = new List<string>();
-
var commandText = "Select Value From ItemValues where " + typeClause;
if (withItemTypes.Count > 0)
@@ -4925,24 +4911,24 @@ namespace Emby.Server.Implementations.Data
{
using (var connection = CreateConnection(true))
{
- connection.RunInTransaction(db =>
+ var list = new List<string>();
+
+ using (var statement = PrepareStatementSafe(connection, commandText))
{
- using (var statement = PrepareStatementSafe(db, commandText))
+ foreach (var row in statement.ExecuteQuery())
{
- foreach (var row in statement.ExecuteQuery())
+ if (!row.IsDBNull(0))
{
- if (!row.IsDBNull(0))
- {
- list.Add(row.GetString(0));
- }
+ list.Add(row.GetString(0));
}
}
- }, ReadTransactionMode);
+ }
+
+ LogQueryTime("GetItemValueNames", commandText, now);
+
+ return list;
}
}
- LogQueryTime("GetItemValueNames", commandText, now);
-
- return list;
}
private QueryResult<Tuple<BaseItem, ItemCounts>> GetItemValues(InternalItemsQuery query, int[] itemValueTypes, string returnType)
@@ -5086,9 +5072,6 @@ namespace Emby.Server.Implementations.Data
var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0;
- var list = new List<Tuple<BaseItem, ItemCounts>>();
- var result = new QueryResult<Tuple<BaseItem, ItemCounts>>();
-
var statementTexts = new List<string>();
if (!isReturningZeroItems)
{
@@ -5107,9 +5090,13 @@ namespace Emby.Server.Implementations.Data
{
using (var connection = CreateConnection(true))
{
- connection.RunInTransaction(db =>
+ return connection.RunInTransaction(db =>
{
- var statements = PrepareAllSafe(db, string.Join(";", statementTexts.ToArray())).ToList();
+ var list = new List<Tuple<BaseItem, ItemCounts>>();
+ var result = new QueryResult<Tuple<BaseItem, ItemCounts>>();
+
+ var statements = PrepareAllSafe(db, statementTexts)
+ .ToList();
if (!isReturningZeroItems)
{
@@ -5172,17 +5159,18 @@ namespace Emby.Server.Implementations.Data
LogQueryTime("GetItemValues", commandText, now);
}
}
+
+ if (result.TotalRecordCount == 0)
+ {
+ result.TotalRecordCount = list.Count;
+ }
+ result.Items = list.ToArray();
+
+ return result;
+
}, ReadTransactionMode);
}
}
-
- if (result.TotalRecordCount == 0)
- {
- result.TotalRecordCount = list.Count;
- }
- result.Items = list.ToArray();
-
- return result;
}
private ItemCounts GetItemCounts(IReadOnlyList<IResultSetValue> reader, int countStartColumn, List<string> typesToCount)
@@ -5395,8 +5383,6 @@ namespace Emby.Server.Implementations.Data
throw new ArgumentNullException("query");
}
- var list = new List<MediaStream>();
-
var cmdText = "select " + string.Join(",", _mediaStreamSaveColumns) + " from mediastreams where";
cmdText += " ItemId=@ItemId";
@@ -5417,32 +5403,31 @@ namespace Emby.Server.Implementations.Data
{
using (var connection = CreateConnection(true))
{
- connection.RunInTransaction(db =>
+ var list = new List<MediaStream>();
+
+ using (var statement = PrepareStatementSafe(connection, cmdText))
{
- using (var statement = PrepareStatementSafe(db, cmdText))
- {
- statement.TryBind("@ItemId", query.ItemId.ToGuidParamValue());
+ statement.TryBind("@ItemId", query.ItemId.ToGuidParamValue());
- if (query.Type.HasValue)
- {
- statement.TryBind("@StreamType", query.Type.Value.ToString());
- }
+ if (query.Type.HasValue)
+ {
+ statement.TryBind("@StreamType", query.Type.Value.ToString());
+ }
- if (query.Index.HasValue)
- {
- statement.TryBind("@StreamIndex", query.Index.Value);
- }
+ if (query.Index.HasValue)
+ {
+ statement.TryBind("@StreamIndex", query.Index.Value);
+ }
- foreach (var row in statement.ExecuteQuery())
- {
- list.Add(GetMediaStream(row));
- }
+ foreach (var row in statement.ExecuteQuery())
+ {
+ list.Add(GetMediaStream(row));
}
- }, ReadTransactionMode);
+ }
+
+ return list;
}
}
-
- return list;
}
public async Task SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken)
diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
index 7afb5720e9..2e39b038ae 100644
--- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
@@ -42,8 +42,10 @@ namespace Emby.Server.Implementations.Data
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
- public void Initialize(ReaderWriterLockSlim writeLock)
+ public void Initialize(ReaderWriterLockSlim writeLock, ManagedConnection managedConnection)
{
+ _connection = managedConnection;
+
WriteLock.Dispose();
WriteLock = writeLock;
@@ -90,7 +92,7 @@ namespace Emby.Server.Implementations.Data
}
}
- private void ImportUserDataIfNeeded(IDatabaseConnection connection)
+ private void ImportUserDataIfNeeded(ManagedConnection connection)
{
if (!_fileSystem.FileExists(_importFile))
{
@@ -117,7 +119,7 @@ namespace Emby.Server.Implementations.Data
}, TransactionMode);
}
- private void ImportUserData(IDatabaseConnection connection, string file)
+ private void ImportUserData(ManagedConnection connection, string file)
{
SqliteExtensions.Attach(connection, file, "UserDataBackup");
@@ -300,24 +302,18 @@ namespace Emby.Server.Implementations.Data
{
using (var connection = CreateConnection(true))
{
- UserItemData result = null;
-
- connection.RunInTransaction(db =>
+ using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key =@Key and userId=@UserId"))
{
- using (var statement = db.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key =@Key and userId=@UserId"))
+ statement.TryBind("@UserId", userId.ToGuidParamValue());
+ statement.TryBind("@Key", key);
+
+ foreach (var row in statement.ExecuteQuery())
{
- statement.TryBind("@UserId", userId.ToGuidParamValue());
- statement.TryBind("@Key", key);
-
- foreach (var row in statement.ExecuteQuery())
- {
- result = ReadRow(row);
- break;
- }
+ return ReadRow(row);
}
- }, ReadTransactionMode);
+ }
- return result;
+ return null;
}
}
}
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index 2b2c3e000d..d0c473777d 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -459,12 +459,21 @@ namespace Emby.Server.Implementations.Dto
if (dtoOptions.EnableUserData)
{
- dto.UserData = await _userDataRepository.GetUserDataDto(item, dto, user).ConfigureAwait(false);
+ dto.UserData = await _userDataRepository.GetUserDataDto(item, dto, user, dtoOptions.Fields).ConfigureAwait(false);
}
if (!dto.ChildCount.HasValue && item.SourceType == SourceType.Library)
{
- dto.ChildCount = GetChildCount(folder, user);
+ // For these types we can try to optimize and assume these values will be equal
+ if (item is MusicAlbum || item is Season)
+ {
+ dto.ChildCount = dto.RecursiveItemCount;
+ }
+
+ if (dtoOptions.Fields.Contains(ItemFields.ChildCount))
+ {
+ dto.ChildCount = dto.ChildCount ?? GetChildCount(folder, user);
+ }
}
if (fields.Contains(ItemFields.CumulativeRunTimeTicks))
@@ -1151,28 +1160,29 @@ namespace Emby.Server.Implementations.Dto
{
dto.Artists = hasArtist.Artists;
- var artistItems = _libraryManager.GetArtists(new InternalItemsQuery
- {
- EnableTotalRecordCount = false,
- ItemIds = new[] { item.Id.ToString("N") }
- });
-
- dto.ArtistItems = artistItems.Items
- .Select(i =>
- {
- var artist = i.Item1;
- return new NameIdPair
- {
- Name = artist.Name,
- Id = artist.Id.ToString("N")
- };
- })
- .ToList();
+ //var artistItems = _libraryManager.GetArtists(new InternalItemsQuery
+ //{
+ // EnableTotalRecordCount = false,
+ // ItemIds = new[] { item.Id.ToString("N") }
+ //});
+
+ //dto.ArtistItems = artistItems.Items
+ // .Select(i =>
+ // {
+ // var artist = i.Item1;
+ // return new NameIdPair
+ // {
+ // Name = artist.Name,
+ // Id = artist.Id.ToString("N")
+ // };
+ // })
+ // .ToList();
// Include artists that are not in the database yet, e.g., just added via metadata editor
- var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
+ //var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
+ dto.ArtistItems = new List<NameIdPair>();
dto.ArtistItems.AddRange(hasArtist.Artists
- .Except(foundArtists, new DistinctNameComparer())
+ //.Except(foundArtists, new DistinctNameComparer())
.Select(i =>
{
// This should not be necessary but we're seeing some cases of it
@@ -1201,23 +1211,48 @@ namespace Emby.Server.Implementations.Dto
{
dto.AlbumArtist = hasAlbumArtist.AlbumArtists.FirstOrDefault();
- var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery
- {
- EnableTotalRecordCount = false,
- ItemIds = new[] { item.Id.ToString("N") }
- });
-
- dto.AlbumArtists = artistItems.Items
+ //var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery
+ //{
+ // EnableTotalRecordCount = false,
+ // ItemIds = new[] { item.Id.ToString("N") }
+ //});
+
+ //dto.AlbumArtists = artistItems.Items
+ // .Select(i =>
+ // {
+ // var artist = i.Item1;
+ // return new NameIdPair
+ // {
+ // Name = artist.Name,
+ // Id = artist.Id.ToString("N")
+ // };
+ // })
+ // .ToList();
+
+ dto.AlbumArtists = new List<NameIdPair>();
+ dto.AlbumArtists.AddRange(hasAlbumArtist.AlbumArtists
+ //.Except(foundArtists, new DistinctNameComparer())
.Select(i =>
{
- var artist = i.Item1;
- return new NameIdPair
+ // This should not be necessary but we're seeing some cases of it
+ if (string.IsNullOrWhiteSpace(i))
{
- Name = artist.Name,
- Id = artist.Id.ToString("N")
- };
- })
- .ToList();
+ return null;
+ }
+
+ var artist = _libraryManager.GetArtist(i);
+ if (artist != null)
+ {
+ return new NameIdPair
+ {
+ Name = artist.Name,
+ Id = artist.Id.ToString("N")
+ };
+ }
+
+ return null;
+
+ }).Where(i => i != null));
}
// Add video info
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index e478b9d817..df0301fc35 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -51,6 +51,7 @@
<Compile Include="Connect\ConnectManager.cs" />
<Compile Include="Connect\Responses.cs" />
<Compile Include="Connect\Validator.cs" />
+ <Compile Include="Data\ManagedConnection.cs" />
<Compile Include="Data\SqliteDisplayPreferencesRepository.cs" />
<Compile Include="Data\SqliteFileOrganizationRepository.cs" />
<Compile Include="Data\SqliteItemRepository.cs" />
@@ -180,6 +181,7 @@
<Compile Include="Localization\LocalizationManager.cs" />
<Compile Include="MediaEncoder\EncodingManager.cs" />
<Compile Include="Migrations\IVersionMigration.cs" />
+ <Compile Include="Migrations\LibraryScanMigration.cs" />
<Compile Include="Migrations\UpdateLevelMigration.cs" />
<Compile Include="News\NewsEntryPoint.cs" />
<Compile Include="News\NewsService.cs" />
diff --git a/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
index cc2dcb6fd1..5bb21d02ac 100644
--- a/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
+++ b/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
@@ -519,6 +519,12 @@ namespace Emby.Server.Implementations.FileOrganization
private void PerformFileSorting(TvFileOrganizationOptions options, FileOrganizationResult result)
{
+ // We should probably handle this earlier so that we never even make it this far
+ if (string.Equals(result.OriginalPath, result.TargetPath, StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+
_libraryMonitor.ReportFileSystemChangeBeginning(result.TargetPath);
_fileSystem.CreateDirectory(Path.GetDirectoryName(result.TargetPath));
diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
index 94cc383a7a..4606d0e316 100644
--- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
+++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
@@ -76,7 +76,8 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
private void ProcessContext(HttpListenerContext context)
{
- Task.Factory.StartNew(() => InitTask(context));
+ //Task.Factory.StartNew(() => InitTask(context), TaskCreationOptions.DenyChildAttach | TaskCreationOptions.PreferFairness);
+ Task.Run(() => InitTask(context));
}
private Task InitTask(HttpListenerContext context)
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index ad91988e53..1ff61286f9 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -817,7 +817,31 @@ namespace Emby.Server.Implementations.Library
return _userRootFolder;
}
-
+
+ public Guid? FindIdByPath(string path, bool? isFolder)
+ {
+ // If this returns multiple items it could be tricky figuring out which one is correct.
+ // In most cases, the newest one will be and the others obsolete but not yet cleaned up
+
+ var query = new InternalItemsQuery
+ {
+ Path = path,
+ IsFolder = isFolder,
+ SortBy = new[] { ItemSortBy.DateCreated },
+ SortOrder = SortOrder.Descending,
+ Limit = 1
+ };
+
+ var id = GetItemIds(query);
+
+ if (id.Count == 0)
+ {
+ return null;
+ }
+
+ return id[0];
+ }
+
public BaseItem FindByPath(string path, bool? isFolder)
{
// If this returns multiple items it could be tricky figuring out which one is correct.
@@ -1430,7 +1454,7 @@ namespace Emby.Server.Implementations.Library
}))
{
// Optimize by querying against top level views
- query.TopParentIds = parents.SelectMany(i => GetTopParentsForQuery(i, query.User)).Select(i => i.Id.ToString("N")).ToArray();
+ query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).Select(i => i.ToString("N")).ToArray();
query.AncestorIds = new string[] { };
}
}
@@ -1489,7 +1513,7 @@ namespace Emby.Server.Implementations.Library
}))
{
// Optimize by querying against top level views
- query.TopParentIds = parents.SelectMany(i => GetTopParentsForQuery(i, query.User)).Select(i => i.Id.ToString("N")).ToArray();
+ query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).Select(i => i.ToString("N")).ToArray();
}
else
{
@@ -1515,11 +1539,11 @@ namespace Emby.Server.Implementations.Library
}, CancellationToken.None).Result.ToList();
- query.TopParentIds = userViews.SelectMany(i => GetTopParentsForQuery(i, user)).Select(i => i.Id.ToString("N")).ToArray();
+ query.TopParentIds = userViews.SelectMany(i => GetTopParentIdsForQuery(i, user)).Select(i => i.ToString("N")).ToArray();
}
}
- private IEnumerable<BaseItem> GetTopParentsForQuery(BaseItem item, User user)
+ private IEnumerable<Guid> GetTopParentIdsForQuery(BaseItem item, User user)
{
var view = item as UserView;
@@ -1527,7 +1551,7 @@ namespace Emby.Server.Implementations.Library
{
if (string.Equals(view.ViewType, CollectionType.LiveTv))
{
- return new[] { view };
+ return new[] { view.Id };
}
if (string.Equals(view.ViewType, CollectionType.Channels))
{
@@ -1537,7 +1561,7 @@ namespace Emby.Server.Implementations.Library
}, CancellationToken.None).Result;
- return channelResult.Items;
+ return channelResult.Items.Select(i => i.Id);
}
// Translate view into folders
@@ -1546,18 +1570,18 @@ namespace Emby.Server.Implementations.Library
var displayParent = GetItemById(view.DisplayParentId);
if (displayParent != null)
{
- return GetTopParentsForQuery(displayParent, user);
+ return GetTopParentIdsForQuery(displayParent, user);
}
- return new BaseItem[] { };
+ return new Guid[] { };
}
if (view.ParentId != Guid.Empty)
{
var displayParent = GetItemById(view.ParentId);
if (displayParent != null)
{
- return GetTopParentsForQuery(displayParent, user);
+ return GetTopParentIdsForQuery(displayParent, user);
}
- return new BaseItem[] { };
+ return new Guid[] { };
}
// Handle grouping
@@ -1568,23 +1592,23 @@ namespace Emby.Server.Implementations.Library
.OfType<CollectionFolder>()
.Where(i => string.IsNullOrWhiteSpace(i.CollectionType) || string.Equals(i.CollectionType, view.ViewType, StringComparison.OrdinalIgnoreCase))
.Where(i => user.IsFolderGrouped(i.Id))
- .SelectMany(i => GetTopParentsForQuery(i, user));
+ .SelectMany(i => GetTopParentIdsForQuery(i, user));
}
- return new BaseItem[] { };
+ return new Guid[] { };
}
var collectionFolder = item as CollectionFolder;
if (collectionFolder != null)
{
- return collectionFolder.GetPhysicalParents();
+ return collectionFolder.PhysicalFolderIds;
}
-
+
var topParent = item.GetTopParent();
if (topParent != null)
{
- return new[] { topParent };
+ return new[] { topParent.Id };
}
- return new BaseItem[] { };
+ return new Guid[] { };
}
/// <summary>
diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs
index f4a30fc00b..5a14edf135 100644
--- a/Emby.Server.Implementations/Library/UserDataManager.cs
+++ b/Emby.Server.Implementations/Library/UserDataManager.cs
@@ -12,6 +12,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Library
{
@@ -186,16 +187,16 @@ namespace Emby.Server.Implementations.Library
var userData = GetUserData(user.Id, item);
var dto = GetUserItemDataDto(userData);
- await item.FillUserDataDtoValues(dto, userData, null, user).ConfigureAwait(false);
+ await item.FillUserDataDtoValues(dto, userData, null, user, new List<ItemFields>()).ConfigureAwait(false);
return dto;
}
- public async Task<UserItemDataDto> GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user)
+ public async Task<UserItemDataDto> GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, List<ItemFields> fields)
{
var userData = GetUserData(user.Id, item);
var dto = GetUserItemDataDto(userData);
- await item.FillUserDataDtoValues(dto, userData, itemDto, user).ConfigureAwait(false);
+ await item.FillUserDataDtoValues(dto, userData, itemDto, user, fields).ConfigureAwait(false);
return dto;
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index f5bef058d2..84a255c7a9 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -328,15 +328,35 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
await UpdateTimersForSeriesTimer(epgData, timer, true).ConfigureAwait(false);
}
+ }
+ public async Task RefreshTimers(CancellationToken cancellationToken, IProgress<double> progress)
+ {
var timers = await GetTimersAsync(cancellationToken).ConfigureAwait(false);
- foreach (var timer in timers.ToList())
+ foreach (var timer in timers)
{
if (DateTime.UtcNow > timer.EndDate && !_activeRecordings.ContainsKey(timer.Id))
{
OnTimerOutOfDate(timer);
+ continue;
+ }
+
+ if (string.IsNullOrWhiteSpace(timer.ProgramId) || string.IsNullOrWhiteSpace(timer.ChannelId))
+ {
+ continue;
+ }
+
+ var epg = GetEpgDataForChannel(timer.ChannelId);
+ var program = epg.FirstOrDefault(i => string.Equals(i.Id, timer.ProgramId, StringComparison.OrdinalIgnoreCase));
+ if (program == null)
+ {
+ OnTimerOutOfDate(timer);
+ continue;
}
+
+ RecordingHelper.CopyProgramInfoToTimerInfo(program, timer);
+ _timerProvider.Update(timer);
}
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
index 881aaaf0d6..a5b19ff524 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
@@ -41,6 +41,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public static void CopyProgramInfoToTimerInfo(ProgramInfo programInfo, TimerInfo timerInfo)
{
+ timerInfo.Name = programInfo.Name;
+ timerInfo.StartDate = programInfo.StartDate;
+ timerInfo.EndDate = programInfo.EndDate;
+ timerInfo.ChannelId = programInfo.ChannelId;
+
timerInfo.SeasonNumber = programInfo.SeasonNumber;
timerInfo.EpisodeNumber = programInfo.EpisodeNumber;
timerInfo.IsMovie = programInfo.IsMovie;
@@ -54,6 +59,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
timerInfo.HomePageUrl = programInfo.HomePageUrl;
timerInfo.CommunityRating = programInfo.CommunityRating;
+ timerInfo.Overview = programInfo.Overview;
timerInfo.ShortOverview = programInfo.ShortOverview;
timerInfo.OfficialRating = programInfo.OfficialRating;
timerInfo.IsRepeat = programInfo.IsRepeat;
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index faf9687f40..5e12fc9b98 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -1231,6 +1231,7 @@ namespace Emby.Server.Implementations.LiveTv
if (coreService != null)
{
await coreService.RefreshSeriesTimers(cancellationToken, new Progress<double>()).ConfigureAwait(false);
+ await coreService.RefreshTimers(cancellationToken, new Progress<double>()).ConfigureAwait(false);
}
// Load these now which will prefetch metadata
diff --git a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
index 43e19da65a..f18278cb25 100644
--- a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
+++ b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
@@ -65,9 +65,9 @@ namespace Emby.Server.Implementations.Notifications
var whereClause = " where " + string.Join(" And ", clauses.ToArray());
- using (var connection = CreateConnection(true))
+ using (WriteLock.Read())
{
- lock (WriteLock)
+ using (var connection = CreateConnection(true))
{
result.TotalRecordCount = connection.Query("select count(Id) from Notifications" + whereClause, paramList.ToArray()).SelectScalarInt().First();
@@ -106,9 +106,9 @@ namespace Emby.Server.Implementations.Notifications
{
var result = new NotificationsSummary();
- using (var connection = CreateConnection(true))
+ using (WriteLock.Read())
{
- lock (WriteLock)
+ using (var connection = CreateConnection(true))
{
using (var statement = connection.PrepareStatement("select Level from Notifications where UserId=@UserId and IsRead=@IsRead"))
{
@@ -223,9 +223,9 @@ namespace Emby.Server.Implementations.Notifications
cancellationToken.ThrowIfCancellationRequested();
- using (var connection = CreateConnection())
+ lock (WriteLock)
{
- lock (WriteLock)
+ using (var connection = CreateConnection())
{
connection.RunInTransaction(conn =>
{
@@ -286,9 +286,9 @@ namespace Emby.Server.Implementations.Notifications
{
cancellationToken.ThrowIfCancellationRequested();
- using (var connection = CreateConnection())
+ using (WriteLock.Write())
{
- lock (WriteLock)
+ using (var connection = CreateConnection())
{
connection.RunInTransaction(conn =>
{
@@ -308,9 +308,9 @@ namespace Emby.Server.Implementations.Notifications
{
cancellationToken.ThrowIfCancellationRequested();
- using (var connection = CreateConnection())
+ using (WriteLock.Write())
{
- lock (WriteLock)
+ using (var connection = CreateConnection())
{
connection.RunInTransaction(conn =>
{
diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs
index 392db69353..a2d61873b8 100644
--- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs
+++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs
@@ -206,15 +206,15 @@ namespace Emby.Server.Implementations.Security
{
using (var connection = CreateConnection(true))
{
- var result = new QueryResult<AuthenticationInfo>();
-
- connection.RunInTransaction(db =>
+ return connection.RunInTransaction(db =>
{
+ var result = new QueryResult<AuthenticationInfo>();
+
var statementTexts = new List<string>();
statementTexts.Add(commandText);
statementTexts.Add("select count (Id) from AccessTokens" + whereTextWithoutPaging);
- var statements = PrepareAllSafe(db, string.Join(";", statementTexts.ToArray()))
+ var statements = PrepareAllSafe(db, statementTexts)
.ToList();
using (var statement = statements[0])
@@ -236,10 +236,10 @@ namespace Emby.Server.Implementations.Security
}
}
- }, ReadTransactionMode);
+ result.Items = list.ToArray();
+ return result;
- result.Items = list.ToArray();
- return result;
+ }, ReadTransactionMode);
}
}
}
diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs
index 363fe55935..5e6de1d4db 100644
--- a/Emby.Server.Implementations/TV/TVSeriesManager.cs
+++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs
@@ -143,7 +143,7 @@ namespace Emby.Server.Implementations.TV
// If viewing all next up for all series, remove first episodes
// But if that returns empty, keep those first episodes (avoid completely empty view)
- var alwaysEnableFirstEpisode = string.IsNullOrWhiteSpace(request.SeriesId);
+ var alwaysEnableFirstEpisode = !string.IsNullOrWhiteSpace(request.SeriesId);
var isFirstItemAFirstEpisode = true;
return allNextUp
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index 73a2bedb9a..7a8951396a 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -121,7 +121,9 @@ namespace MediaBrowser.Api
{
var options = new DtoOptions();
- options.DeviceId = authContext.GetAuthorizationInfo(Request).DeviceId;
+ var authInfo = authContext.GetAuthorizationInfo(Request);
+
+ options.DeviceId = authInfo.DeviceId;
var hasFields = request as IHasItemFields;
if (hasFields != null)
@@ -129,6 +131,34 @@ namespace MediaBrowser.Api
options.Fields = hasFields.GetItemFields().ToList();
}
+ var client = authInfo.Client ?? string.Empty;
+ if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 ||
+ client.IndexOf("wmc", StringComparison.OrdinalIgnoreCase) != -1 ||
+ client.IndexOf("media center", StringComparison.OrdinalIgnoreCase) != -1 ||
+ client.IndexOf("classic", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ options.Fields.Add(Model.Querying.ItemFields.RecursiveItemCount);
+ }
+
+ if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 ||
+ client.IndexOf("wmc", StringComparison.OrdinalIgnoreCase) != -1 ||
+ client.IndexOf("media center", StringComparison.OrdinalIgnoreCase) != -1 ||
+ client.IndexOf("classic", StringComparison.OrdinalIgnoreCase) != -1 ||
+ client.IndexOf("roku", StringComparison.OrdinalIgnoreCase) != -1 ||
+ client.IndexOf("samsung", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ options.Fields.Add(Model.Querying.ItemFields.ChildCount);
+ }
+
+ if (client.IndexOf("web", StringComparison.OrdinalIgnoreCase) == -1 &&
+ client.IndexOf("mobile", StringComparison.OrdinalIgnoreCase) == -1 &&
+ client.IndexOf("ios", StringComparison.OrdinalIgnoreCase) == -1 &&
+ client.IndexOf("android", StringComparison.OrdinalIgnoreCase) == -1 &&
+ client.IndexOf("theater", StringComparison.OrdinalIgnoreCase) == -1)
+ {
+ options.Fields.Add(Model.Querying.ItemFields.ChildCount);
+ }
+
var hasDtoOptions = request as IHasDtoOptions;
if (hasDtoOptions != null)
{
diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs
index 0ae1fbff41..b5c51bfef0 100644
--- a/MediaBrowser.Api/ItemLookupService.cs
+++ b/MediaBrowser.Api/ItemLookupService.cs
@@ -14,8 +14,6 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
@@ -88,6 +86,12 @@ namespace MediaBrowser.Api
{
}
+ [Route("/Items/RemoteSearch/Book", "POST")]
+ [Authenticated]
+ public class GetBookRemoteSearchResults : RemoteSearchQuery<BookInfo>, IReturn<List<RemoteSearchResult>>
+ {
+ }
+
[Route("/Items/RemoteSearch/Image", "GET", Summary = "Gets a remote image")]
public class GetRemoteSearchImage
{
@@ -147,6 +151,13 @@ namespace MediaBrowser.Api
return ToOptimizedResult(result);
}
+ public async Task<object> Post(GetBookRemoteSearchResults request)
+ {
+ var result = await _providerManager.GetRemoteSearchResults<Book, BookInfo>(request, CancellationToken.None).ConfigureAwait(false);
+
+ return ToOptimizedResult(result);
+ }
+
public async Task<object> Post(GetMovieRemoteSearchResults request)
{
var result = await _providerManager.GetRemoteSearchResults<Movie, MovieInfo>(request, CancellationToken.None).ConfigureAwait(false);
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 3718edba49..288553ade0 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -2358,7 +2358,8 @@ namespace MediaBrowser.Api.Playback
state.TargetVideoStreamCount,
state.TargetAudioStreamCount,
state.TargetVideoCodecTag,
- state.IsTargetAVC);
+ state.IsTargetAVC,
+ state.AllAudioCodecs);
if (mediaProfile != null)
{
@@ -2580,7 +2581,8 @@ namespace MediaBrowser.Api.Playback
state.TargetVideoStreamCount,
state.TargetAudioStreamCount,
state.TargetVideoCodecTag,
- state.IsTargetAVC
+ state.IsTargetAVC,
+ state.AllAudioCodecs
).FirstOrDefault() ?? string.Empty;
}
diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs
index 003599390e..9c337781cb 100644
--- a/MediaBrowser.Api/Playback/StreamState.cs
+++ b/MediaBrowser.Api/Playback/StreamState.cs
@@ -11,6 +11,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
+using System.Linq;
using System.Threading;
namespace MediaBrowser.Api.Playback
@@ -244,6 +245,17 @@ namespace MediaBrowser.Api.Playback
public int? OutputAudioBitrate;
public int? OutputVideoBitrate;
+ public List<string> AllAudioCodecs
+ {
+ get
+ {
+ return MediaSource.MediaStreams.Where(i => i.Type == MediaStreamType.Audio)
+ .Select(i => i.Codec)
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .ToList();
+ }
+ }
+
public string ActualOutputVideoCodec
{
get
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 9f45034665..2aa53d6515 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -30,6 +30,7 @@ using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Providers;
+using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities
@@ -2191,7 +2192,7 @@ namespace MediaBrowser.Controller.Entities
return path;
}
- public virtual Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user)
+ public virtual Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List<ItemFields> itemFields)
{
if (RunTimeTicks.HasValue)
{
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index ebc55ca8a0..c505aefb3f 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -27,6 +27,7 @@ namespace MediaBrowser.Controller.Entities
public CollectionFolder()
{
PhysicalLocationsList = new List<string>();
+ PhysicalFolderIds = new List<Guid>();
}
[IgnoreDataMember]
@@ -153,6 +154,7 @@ namespace MediaBrowser.Controller.Entities
}
public List<string> PhysicalLocationsList { get; set; }
+ public List<Guid> PhysicalFolderIds { get; set; }
protected override IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
{
@@ -176,6 +178,18 @@ namespace MediaBrowser.Controller.Entities
}
}
+ if (!changed)
+ {
+ var folderIds = PhysicalFolderIds.ToList();
+
+ var newFolderIds = GetPhysicalFolders(false).Select(i => i.Id).ToList();
+
+ if (!folderIds.SequenceEqual(newFolderIds))
+ {
+ changed = true;
+ }
+ }
+
return changed;
}
@@ -186,6 +200,31 @@ namespace MediaBrowser.Controller.Entities
return changed;
}
+ protected override bool RefreshLinkedChildren(IEnumerable<FileSystemMetadata> fileSystemChildren)
+ {
+ var physicalFolders = GetPhysicalFolders(false)
+ .ToList();
+
+ var linkedChildren = physicalFolders
+ .SelectMany(c => c.LinkedChildren)
+ .ToList();
+
+ var changed = !linkedChildren.SequenceEqual(LinkedChildren, new LinkedChildComparer());
+
+ LinkedChildren = linkedChildren;
+
+ var folderIds = PhysicalFolderIds.ToList();
+ var newFolderIds = physicalFolders.Select(i => i.Id).ToList();
+
+ if (!folderIds.SequenceEqual(newFolderIds))
+ {
+ changed = true;
+ PhysicalFolderIds = newFolderIds.ToList();
+ }
+
+ return changed;
+ }
+
internal override bool IsValidFromResolver(BaseItem newItem)
{
var newCollectionFolder = newItem as CollectionFolder;
@@ -263,26 +302,6 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Our children are actually just references to the ones in the physical root...
/// </summary>
- /// <value>The linked children.</value>
- [IgnoreDataMember]
- public override List<LinkedChild> LinkedChildren
- {
- get { return GetLinkedChildrenInternal(); }
- set
- {
- base.LinkedChildren = value;
- }
- }
- private List<LinkedChild> GetLinkedChildrenInternal()
- {
- return GetPhysicalParents()
- .SelectMany(c => c.LinkedChildren)
- .ToList();
- }
-
- /// <summary>
- /// Our children are actually just references to the ones in the physical root...
- /// </summary>
/// <value>The actual children.</value>
[IgnoreDataMember]
protected override IEnumerable<BaseItem> ActualChildren
@@ -292,11 +311,16 @@ namespace MediaBrowser.Controller.Entities
private IEnumerable<BaseItem> GetActualChildren()
{
- return GetPhysicalParents().SelectMany(c => c.Children);
+ return GetPhysicalFolders(true).SelectMany(c => c.Children);
}
- public IEnumerable<Folder> GetPhysicalParents()
+ private IEnumerable<Folder> GetPhysicalFolders(bool enableCache)
{
+ if (enableCache)
+ {
+ return PhysicalFolderIds.Select(i => LibraryManager.GetItemById(i)).OfType<Folder>();
+ }
+
var rootChildren = LibraryManager.RootFolder.Children
.OfType<Folder>()
.ToList();
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 4705f03fa0..a84e9a5d23 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -1222,7 +1222,7 @@ namespace MediaBrowser.Controller.Entities
/// Refreshes the linked children.
/// </summary>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
- private bool RefreshLinkedChildren(IEnumerable<FileSystemMetadata> fileSystemChildren)
+ protected virtual bool RefreshLinkedChildren(IEnumerable<FileSystemMetadata> fileSystemChildren)
{
var currentManualLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Manual).ToList();
var currentShortcutLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut).ToList();
@@ -1410,23 +1410,24 @@ namespace MediaBrowser.Controller.Entities
}
}
- public override async Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user)
+ public override async Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List<ItemFields> itemFields)
{
if (!SupportsUserDataFromChildren)
{
return;
}
- var recursiveItemCount = GetRecursiveChildCount(user);
-
if (itemDto != null)
{
- itemDto.RecursiveItemCount = recursiveItemCount;
+ if (itemFields.Contains(ItemFields.RecursiveItemCount))
+ {
+ itemDto.RecursiveItemCount = GetRecursiveChildCount(user);
+ }
}
- if (recursiveItemCount > 0 && SupportsPlayedStatus)
+ if (SupportsPlayedStatus)
{
- var unplayedQueryResult = recursiveItemCount > 0 ? await GetItems(new InternalItemsQuery(user)
+ var unplayedQueryResult = await GetItems(new InternalItemsQuery(user)
{
Recursive = true,
IsFolder = false,
@@ -1435,21 +1436,24 @@ namespace MediaBrowser.Controller.Entities
Limit = 0,
IsPlayed = false
- }).ConfigureAwait(false) : new QueryResult<BaseItem>();
+ }).ConfigureAwait(false);
double unplayedCount = unplayedQueryResult.TotalRecordCount;
- var unplayedPercentage = (unplayedCount / recursiveItemCount) * 100;
- dto.PlayedPercentage = 100 - unplayedPercentage;
- dto.Played = dto.PlayedPercentage.Value >= 100;
dto.UnplayedItemCount = unplayedQueryResult.TotalRecordCount;
- }
- if (itemDto != null)
- {
- if (this is Season || this is MusicAlbum)
+ if (itemDto != null && itemDto.RecursiveItemCount.HasValue)
+ {
+ if (itemDto.RecursiveItemCount.Value > 0)
+ {
+ var unplayedPercentage = (unplayedCount/itemDto.RecursiveItemCount.Value)*100;
+ dto.PlayedPercentage = 100 - unplayedPercentage;
+ dto.Played = dto.PlayedPercentage.Value >= 100;
+ }
+ }
+ else
{
- itemDto.ChildCount = recursiveItemCount;
+ dto.Played = (dto.UnplayedItemCount ?? 0) == 0;
}
}
}
diff --git a/MediaBrowser.Controller/Entities/IHasUserData.cs b/MediaBrowser.Controller/Entities/IHasUserData.cs
index c21e170ae7..0b3b7dc8d9 100644
--- a/MediaBrowser.Controller/Entities/IHasUserData.cs
+++ b/MediaBrowser.Controller/Entities/IHasUserData.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Entities
{
@@ -14,10 +15,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Fills the user data dto values.
/// </summary>
- /// <param name="dto">The dto.</param>
- /// <param name="userData">The user data.</param>
- /// <param name="user">The user.</param>
- Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user);
+ Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List<ItemFields> fields);
bool EnableRememberingTrackSelections { get; }
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index d297fd0065..bf9a076264 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -62,6 +62,8 @@ namespace MediaBrowser.Controller.Library
/// <returns>BaseItem.</returns>
BaseItem FindByPath(string path, bool? isFolder);
+ Guid? FindIdByPath(string path, bool? isFolder);
+
/// <summary>
/// Gets the artist.
/// </summary>
diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs
index 86c52c4c31..5940c7e292 100644
--- a/MediaBrowser.Controller/Library/IUserDataManager.cs
+++ b/MediaBrowser.Controller/Library/IUserDataManager.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Model.Entities;
using System;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Library
{
@@ -37,12 +38,9 @@ namespace MediaBrowser.Controller.Library
/// <summary>
/// Gets the user data dto.
/// </summary>
- /// <param name="item">The item.</param>
- /// <param name="user">The user.</param>
- /// <returns>UserItemDataDto.</returns>
Task<UserItemDataDto> GetUserDataDto(IHasUserData item, User user);
- Task<UserItemDataDto> GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user);
+ Task<UserItemDataDto> GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, List<ItemFields> fields);
/// <summary>
/// Get all user data for the given user
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
index 0c7ff1b760..145337a2a4 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs
@@ -11,6 +11,7 @@ using MediaBrowser.Model.Net;
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -117,6 +118,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
+ public List<string> AllAudioCodecs
+ {
+ get
+ {
+ return MediaSource.MediaStreams.Where(i => i.Type == MediaStreamType.Audio)
+ .Select(i => i.Codec)
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .ToList();
+ }
+ }
+
private void DisposeIsoMount()
{
if (IsoMount != null)
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
index e197bdb6fd..70d02901ec 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
@@ -846,7 +846,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.TargetVideoStreamCount,
state.TargetAudioStreamCount,
state.TargetVideoCodecTag,
- state.IsTargetAVC);
+ state.IsTargetAVC,
+ state.AllAudioCodecs);
if (mediaProfile != null)
{
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 35677813d8..493fe1bd24 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -191,7 +191,6 @@ namespace MediaBrowser.Model.Configuration
public int SharingExpirationDays { get; set; }
public int SchemaVersion { get; set; }
- public int SqliteCacheSize { get; set; }
public bool EnableAnonymousUsageReporting { get; set; }
public bool EnableStandaloneMusicKeys { get; set; }
@@ -202,6 +201,7 @@ namespace MediaBrowser.Model.Configuration
public bool DisplayCollectionsView { get; set; }
public string[] LocalNetworkAddresses { get; set; }
public string[] CodecsUsed { get; set; }
+ public string[] Migrations { get; set; }
public bool EnableChannelView { get; set; }
public bool EnableExternalContentInSuggestions { get; set; }
public bool EnableSimpleArtistDetection { get; set; }
@@ -214,7 +214,7 @@ namespace MediaBrowser.Model.Configuration
{
LocalNetworkAddresses = new string[] { };
CodecsUsed = new string[] { };
- SqliteCacheSize = 0;
+ Migrations = new string[] { };
ImageExtractionTimeoutMs = 0;
EnableLocalizedGuids = true;
diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
index 1fbb4ffa17..aa0b6f4319 100644
--- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs
+++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
@@ -1,7 +1,9 @@
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.MediaInfo;
using System;
+using System.Collections.Generic;
using System.Globalization;
+using System.Linq;
namespace MediaBrowser.Model.Dlna
{
@@ -22,12 +24,15 @@ namespace MediaBrowser.Model.Dlna
int? numVideoStreams,
int? numAudioStreams,
string videoCodecTag,
- bool? isAvc)
+ bool? isAvc,
+ List<string> allAudioCodecs )
{
switch (condition.Property)
{
case ProfileConditionValue.IsAnamorphic:
return IsConditionSatisfied(condition, isAnamorphic);
+ case ProfileConditionValue.HasAudioCodec:
+ return IsHasAudioCodecConditionSatisfied(condition, allAudioCodecs);
case ProfileConditionValue.IsAvc:
return IsConditionSatisfied(condition, isAvc);
case ProfileConditionValue.VideoFramerate:
@@ -162,6 +167,25 @@ namespace MediaBrowser.Model.Dlna
}
}
+ private bool IsHasAudioCodecConditionSatisfied(ProfileCondition condition, List<string> allAudioCodecs)
+ {
+ if (allAudioCodecs.Count == 0)
+ {
+ // If the value is unknown, it satisfies if not marked as required
+ return !condition.IsRequired;
+ }
+
+ switch (condition.Condition)
+ {
+ case ProfileConditionType.Equals:
+ return allAudioCodecs.Contains(condition.Value, StringComparer.Ordinal);
+ case ProfileConditionType.NotEquals:
+ return !allAudioCodecs.Contains(condition.Value, StringComparer.Ordinal);
+ default:
+ throw new InvalidOperationException("Unexpected ProfileConditionType");
+ }
+ }
+
private bool IsConditionSatisfied(ProfileCondition condition, bool? currentValue)
{
if (!currentValue.HasValue)
diff --git a/MediaBrowser.Model/Dlna/ContainerProfile.cs b/MediaBrowser.Model/Dlna/ContainerProfile.cs
index d9b75dfc23..35d7ada6b9 100644
--- a/MediaBrowser.Model/Dlna/ContainerProfile.cs
+++ b/MediaBrowser.Model/Dlna/ContainerProfile.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Xml.Serialization;
using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Model.Dlna
{
@@ -27,5 +28,12 @@ namespace MediaBrowser.Model.Dlna
}
return list;
}
+
+ public bool ContainsContainer(string container)
+ {
+ List<string> containers = GetContainers();
+
+ return containers.Count == 0 || ListHelper.ContainsIgnoreCase(containers, container ?? string.Empty);
+ }
}
}
diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
index 4a16a27805..c6a5116b4d 100644
--- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
+++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
@@ -119,7 +119,8 @@ namespace MediaBrowser.Model.Dlna
int? numVideoStreams,
int? numAudioStreams,
string videoCodecTag,
- bool? isAvc)
+ bool? isAvc,
+ List<string> allAudioCodecs)
{
// first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
string orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(runtimeTicks.HasValue, isDirectStream, transcodeSeekInfo);
@@ -161,7 +162,8 @@ namespace MediaBrowser.Model.Dlna
numVideoStreams,
numAudioStreams,
videoCodecTag,
- isAvc);
+ isAvc,
+ allAudioCodecs);
List<string> orgPnValues = new List<string>();
diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs
index 821531ed06..638f78dcbb 100644
--- a/MediaBrowser.Model/Dlna/DeviceProfile.cs
+++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs
@@ -297,7 +297,8 @@ namespace MediaBrowser.Model.Dlna
int? numVideoStreams,
int? numAudioStreams,
string videoCodecTag,
- bool? isAvc)
+ bool? isAvc,
+ List<string> allAudioCodecs)
{
container = StringHelper.TrimStart(container ?? string.Empty, '.');
@@ -331,7 +332,7 @@ namespace MediaBrowser.Model.Dlna
var anyOff = false;
foreach (ProfileCondition c in i.Conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(GetModelProfileCondition(c), width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
+ if (!conditionProcessor.IsVideoConditionSatisfied(GetModelProfileCondition(c), width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc, allAudioCodecs))
{
anyOff = true;
break;
diff --git a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
index 7e2002f179..9d6321c848 100644
--- a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
+++ b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs
@@ -21,6 +21,7 @@
NumVideoStreams = 17,
IsSecondaryAudio = 18,
VideoCodecTag = 19,
- IsAvc = 20
+ IsAvc = 20,
+ HasAudioCodec = 21
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 71f0fd541b..dee1605f36 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Model.Session;
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.Linq;
namespace MediaBrowser.Model.Dlna
{
@@ -409,6 +410,9 @@ namespace MediaBrowser.Model.Dlna
audioStreamIndex = audioStream.Index;
}
+ var allMediaStreams = item.MediaStreams;
+ var allAudioCodecs = allMediaStreams.Where(i => i.Type == MediaStreamType.Audio).Select(i => i.Codec).Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+
MediaStream videoStream = item.VideoStream;
// TODO: This doesn't accout for situation of device being able to handle media bitrate, but wifi connection not fast enough
@@ -424,7 +428,7 @@ namespace MediaBrowser.Model.Dlna
if (isEligibleForDirectPlay || isEligibleForDirectStream)
{
// See if it can be direct played
- PlayMethod? directPlay = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream);
+ PlayMethod? directPlay = GetVideoDirectPlayProfile(options, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream, allMediaStreams);
if (directPlay != null)
{
@@ -552,7 +556,7 @@ namespace MediaBrowser.Model.Dlna
int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio);
int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video);
- if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
+ if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc, allAudioCodecs))
{
LogConditionFailure(options.Profile, "VideoCodecProfile", applyCondition, item);
applyConditions = false;
@@ -653,7 +657,8 @@ namespace MediaBrowser.Model.Dlna
MediaStream videoStream,
MediaStream audioStream,
bool isEligibleForDirectPlay,
- bool isEligibleForDirectStream)
+ bool isEligibleForDirectStream,
+ List<MediaStream> allMediaStreams)
{
DeviceProfile profile = options.Profile;
@@ -701,7 +706,7 @@ namespace MediaBrowser.Model.Dlna
foreach (ContainerProfile i in profile.ContainerProfiles)
{
if (i.Type == DlnaProfileType.Video &&
- ListHelper.ContainsIgnoreCase(i.GetContainers(), container))
+ i.ContainsContainer(container))
{
foreach (ProfileCondition c in i.Conditions)
{
@@ -734,10 +739,12 @@ namespace MediaBrowser.Model.Dlna
int? numAudioStreams = mediaSource.GetStreamCount(MediaStreamType.Audio);
int? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video);
+ var allAudioCodecs = allMediaStreams.Where(i => i.Type == MediaStreamType.Audio).Select(i => i.Codec).Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
+
// Check container conditions
foreach (ProfileCondition i in conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
+ if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc, allAudioCodecs))
{
LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
@@ -764,7 +771,7 @@ namespace MediaBrowser.Model.Dlna
bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
+ if (!conditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc, allAudioCodecs))
{
LogConditionFailure(profile, "VideoCodecProfile", applyCondition, mediaSource);
applyConditions = false;
@@ -784,7 +791,7 @@ namespace MediaBrowser.Model.Dlna
foreach (ProfileCondition i in conditions)
{
- if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
+ if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc, allAudioCodecs))
{
LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index e5dd0353e0..105edb131e 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -6,6 +6,7 @@ using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Session;
using System;
using System.Collections.Generic;
+using System.Linq;
namespace MediaBrowser.Model.Dlna
{
@@ -412,6 +413,17 @@ namespace MediaBrowser.Model.Dlna
}
}
+ public List<string> AllAudioCodecs
+ {
+ get
+ {
+ return MediaSource.MediaStreams.Where(i => i.Type == MediaStreamType.Audio)
+ .Select(i => i.Codec)
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .ToList();
+ }
+ }
+
/// <summary>
/// Returns the video stream that will be used
/// </summary>
diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs
index bf1d4991cf..e36abf16ed 100644
--- a/MediaBrowser.Model/Querying/ItemFields.cs
+++ b/MediaBrowser.Model/Querying/ItemFields.cs
@@ -171,6 +171,8 @@
/// </summary>
PrimaryImageAspectRatio,
+ RecursiveItemCount,
+
/// <summary>
/// The revenue
/// </summary>
diff --git a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
index eb5a5e26a3..e64a7d87c4 100644
--- a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
+++ b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
@@ -307,9 +307,7 @@
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3594.ini" />
<None Include="packages.config" />
</ItemGroup>
- <ItemGroup>
- <Folder Include="Persistence\" />
- </ItemGroup>
+ <ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/MediaBrowser.Server.Startup.Common/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Startup.Common/Persistence/SqliteExtensions.cs
deleted file mode 100644
index 22aeb53dd7..0000000000
--- a/MediaBrowser.Server.Startup.Common/Persistence/SqliteExtensions.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using System;
-using System.Data;
-using System.Data.SQLite;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
-
-namespace Emby.Server.Core.Data
-{
- /// <summary>
- /// Class SQLiteExtensions
- /// </summary>
- public static class SqliteExtensions
- {
- /// <summary>
- /// Connects to db.
- /// </summary>
- public static async Task<IDbConnection> ConnectToDb(string dbPath,
- bool isReadOnly,
- bool enablePooling,
- int? cacheSize,
- ILogger logger)
- {
- if (string.IsNullOrEmpty(dbPath))
- {
- throw new ArgumentNullException("dbPath");
- }
-
- SQLiteConnection.SetMemoryStatus(false);
-
- var connectionstr = new SQLiteConnectionStringBuilder
- {
- PageSize = 4096,
- CacheSize = cacheSize ?? 2000,
- SyncMode = SynchronizationModes.Normal,
- DataSource = dbPath,
- JournalMode = SQLiteJournalModeEnum.Wal,
-
- // This is causing crashing under linux
- Pooling = enablePooling && Environment.OSVersion.Platform == PlatformID.Win32NT,
- ReadOnly = isReadOnly
- };
-
- var connectionString = connectionstr.ConnectionString;
-
- if (!enablePooling)
- {
- logger.Info("Sqlite {0} opening {1}", SQLiteConnection.SQLiteVersion, connectionString);
- }
-
- var connection = new SQLiteConnection(connectionString);
-
- await connection.OpenAsync().ConfigureAwait(false);
-
- return connection;
- }
- }
-}
diff --git a/RSSDP/SsdpDevicePublisherBase.cs b/RSSDP/SsdpDevicePublisherBase.cs
index 260c008960..8ab35d6616 100644
--- a/RSSDP/SsdpDevicePublisherBase.cs
+++ b/RSSDP/SsdpDevicePublisherBase.cs
@@ -291,7 +291,7 @@ namespace Rssdp.Infrastructure
if (devices != null)
{
var deviceList = devices.ToList();
- WriteTrace(String.Format("Sending {0} search responses", deviceList.Count));
+ //WriteTrace(String.Format("Sending {0} search responses", deviceList.Count));
foreach (var device in deviceList)
{
@@ -300,7 +300,7 @@ namespace Rssdp.Infrastructure
}
else
{
- WriteTrace(String.Format("Sending 0 search responses."));
+ //WriteTrace(String.Format("Sending 0 search responses."));
}
});
}
@@ -413,7 +413,7 @@ namespace Rssdp.Infrastructure
//DisposeRebroadcastTimer();
- WriteTrace("Begin Sending Alive Notifications For All Devices");
+ //WriteTrace("Begin Sending Alive Notifications For All Devices");
_LastNotificationTime = DateTime.Now;
@@ -430,7 +430,7 @@ namespace Rssdp.Infrastructure
SendAliveNotifications(device, true);
}
- WriteTrace("Completed Sending Alive Notifications For All Devices");
+ //WriteTrace("Completed Sending Alive Notifications For All Devices");
}
catch (ObjectDisposedException ex)
{
diff --git a/src/Emby.Server/Emby.Server.xproj b/src/Emby.Server/Emby.Server.xproj
index 6a23809ced..2462c5179f 100644
--- a/src/Emby.Server/Emby.Server.xproj
+++ b/src/Emby.Server/Emby.Server.xproj
@@ -37,5 +37,10 @@
<ProjectReference Include="..\..\ServiceStack\ServiceStack.csproj" />
<ProjectReference Include="..\..\SocketHttpListener.Portable\SocketHttpListener.Portable.csproj" />
</ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\SharedVersion.cs">
+ <Link>Properties\SharedVersion.cs</Link>
+ </Compile>
+ </ItemGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project> \ No newline at end of file
diff --git a/src/Emby.Server/project.json b/src/Emby.Server/project.json
index 5b64beae61..852c7d519d 100644
--- a/src/Emby.Server/project.json
+++ b/src/Emby.Server/project.json
@@ -1,5 +1,5 @@
{
- "version": "1.0.0-*",
+ "version": "3.1.0-*",
"buildOptions": {
"emitEntryPoint": true
},
@@ -33,8 +33,26 @@
"win10-arm64": {},
"osx.10.10-x64": {},
"osx.10.11-x64": {},
- "osx.10.12-x64": {},
- "ubuntu.14.04-x64": {}
+ "osx.10.12-x64": ,
+ "rhel.7.0-x64": {},
+ "rhel.7.1-x64": {},
+ "rhel.7.2-x64": {},
+ "ubuntu.14.04-x64": {},
+ "ubuntu.14.10-x64": {},
+ "ubuntu.15.04-x64": {},
+ "ubuntu.15.10-x64": {},
+ "ubuntu.16.04-x64": {},
+ "ubuntu.16.10-x64": {},
+ "centos.7-x64": {},
+ "debian.8-x64": {},
+ "fedora.23-x64": {},
+ "fedora.24-x64": {},
+ "opensuse.13.2-x64": {},
+ "opensuse.42.1-x64": {},
+ "ol.7-x64": {},
+ "ol.7.0-x64": {},
+ "ol.7.1-x64": {},
+ "ol.7.2-x64": {}
},
"frameworks": {