Merge pull request #2340 from MediaBrowser/dev

Dev
This commit is contained in:
Luke 2016-12-13 13:27:53 -05:00 committed by GitHub
commit 6cdbb25b9d
48 changed files with 760 additions and 490 deletions

View file

@ -198,6 +198,12 @@ namespace Emby.Common.Implementations.Networking
return Dns.GetHostAddressesAsync(hostName); return Dns.GetHostAddressesAsync(hostName);
} }
private readonly List<NetworkInterfaceType> _validNetworkInterfaceTypes = new List<NetworkInterfaceType>
{
NetworkInterfaceType.Ethernet,
NetworkInterfaceType.Wireless80211
};
private List<IPAddress> GetIPsDefault() private List<IPAddress> GetIPsDefault()
{ {
NetworkInterface[] interfaces; 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); Logger.Debug("Querying interface: {0}. Type: {1}. Status: {2}", network.Name, network.NetworkInterfaceType, network.OperationalStatus);
var properties = network.GetIPProperties(); var ipProperties = network.GetIPProperties();
return properties.UnicastAddresses // 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 ipProperties.UnicastAddresses
.Where(i => i.IsDnsEligible) .Where(i => i.IsDnsEligible)
.Select(i => i.Address) .Select(i => i.Address)
.Where(i => i.AddressFamily == AddressFamily.InterNetwork) .Where(i => i.AddressFamily == AddressFamily.InterNetwork)

View file

@ -387,6 +387,7 @@ namespace Emby.Common.Implementations.ScheduledTasks
finally finally
{ {
_currentTask = null; _currentTask = null;
GC.Collect();
} }
} }

View file

@ -207,7 +207,8 @@ namespace Emby.Dlna.Didl
streamInfo.TargetVideoStreamCount, streamInfo.TargetVideoStreamCount,
streamInfo.TargetAudioStreamCount, streamInfo.TargetAudioStreamCount,
streamInfo.TargetVideoCodecTag, streamInfo.TargetVideoCodecTag,
streamInfo.IsTargetAVC); streamInfo.IsTargetAVC,
streamInfo.AllAudioCodecs);
foreach (var contentFeature in contentFeatureList) foreach (var contentFeature in contentFeatureList)
{ {
@ -347,7 +348,8 @@ namespace Emby.Dlna.Didl
streamInfo.TargetVideoStreamCount, streamInfo.TargetVideoStreamCount,
streamInfo.TargetAudioStreamCount, streamInfo.TargetAudioStreamCount,
streamInfo.TargetVideoCodecTag, streamInfo.TargetVideoCodecTag,
streamInfo.IsTargetAVC); streamInfo.IsTargetAVC,
streamInfo.AllAudioCodecs);
var filename = url.Substring(0, url.IndexOf('?')); var filename = url.Substring(0, url.IndexOf('?'));

View file

@ -541,7 +541,8 @@ namespace Emby.Dlna.PlayTo
streamInfo.TargetVideoStreamCount, streamInfo.TargetVideoStreamCount,
streamInfo.TargetAudioStreamCount, streamInfo.TargetAudioStreamCount,
streamInfo.TargetVideoCodecTag, streamInfo.TargetVideoCodecTag,
streamInfo.IsTargetAVC); streamInfo.IsTargetAVC,
streamInfo.AllAudioCodecs);
return list.FirstOrDefault(); return list.FirstOrDefault();
} }

View file

@ -489,6 +489,7 @@ namespace Emby.Server.Core
{ {
var migrations = new List<IVersionMigration> var migrations = new List<IVersionMigration>
{ {
new LibraryScanMigration(ServerConfigurationManager, TaskManager)
}; };
foreach (var task in migrations) foreach (var task in migrations)

View file

@ -84,9 +84,6 @@ namespace Emby.Server.Implementations.Activity
{ {
using (var connection = CreateConnection(true)) using (var connection = CreateConnection(true))
{ {
var list = new List<ActivityLogEntry>();
var result = new QueryResult<ActivityLogEntry>();
var commandText = BaseActivitySelectText; var commandText = BaseActivitySelectText;
var whereClauses = new List<string>(); var whereClauses = new List<string>();
@ -127,9 +124,12 @@ namespace Emby.Server.Implementations.Activity
statementTexts.Add(commandText); statementTexts.Add(commandText);
statementTexts.Add("select count (Id) from ActivityLogEntries" + whereTextWithoutPaging); 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]) using (var statement = statements[0])
{ {
@ -153,10 +153,11 @@ namespace Emby.Server.Implementations.Activity
result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First(); result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First();
} }
}, ReadTransactionMode);
result.Items = list.ToArray(); result.Items = list.ToArray();
return result; return result;
}, ReadTransactionMode);
} }
} }
} }

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
@ -25,7 +26,7 @@ namespace Emby.Server.Implementations.Data
protected TransactionMode TransactionMode protected TransactionMode TransactionMode
{ {
get { return TransactionMode.Immediate; } get { return TransactionMode.Deferred; }
} }
protected TransactionMode ReadTransactionMode protected TransactionMode ReadTransactionMode
@ -43,6 +44,8 @@ namespace Emby.Server.Implementations.Data
//CheckOk(rc); //CheckOk(rc);
rc = raw.sqlite3_config(raw.SQLITE_CONFIG_MULTITHREAD, 1); 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); //CheckOk(rc);
rc = raw.sqlite3_enable_shared_cache(1); rc = raw.sqlite3_enable_shared_cache(1);
@ -53,84 +56,125 @@ namespace Emby.Server.Implementations.Data
private static bool _versionLogged; private static bool _versionLogged;
private string _defaultWal; private string _defaultWal;
protected ManagedConnection _connection;
protected SQLiteDatabaseConnection CreateConnection(bool isReadOnly = false) protected virtual bool EnableSingleConnection
{ {
if (!_versionLogged) get { return true; }
}
protected ManagedConnection CreateConnection(bool isReadOnly = false)
{
if (_connection != null)
{ {
_versionLogged = true; return _connection;
Logger.Info("Sqlite version: " + SQLite3.Version);
Logger.Info("Sqlite compiler options: " + string.Join(",", SQLite3.CompilerOptions.ToArray()));
} }
ConnectionFlags connectionFlags; lock (WriteLock)
if (isReadOnly)
{ {
//Logger.Info("Opening read connection"); if (!_versionLogged)
//connectionFlags = ConnectionFlags.ReadOnly;
connectionFlags = ConnectionFlags.Create;
connectionFlags |= ConnectionFlags.ReadWrite;
}
else
{
//Logger.Info("Opening write connection");
connectionFlags = ConnectionFlags.Create;
connectionFlags |= ConnectionFlags.ReadWrite;
}
connectionFlags |= ConnectionFlags.SharedCached;
connectionFlags |= ConnectionFlags.NoMutex;
var db = SQLite3.Open(DbFilePath, connectionFlags, null);
if (string.IsNullOrWhiteSpace(_defaultWal))
{
_defaultWal = db.Query("PRAGMA journal_mode").SelectScalarString().First();
Logger.Info("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal);
}
var queries = new List<string>
{
//"PRAGMA cache size=-10000"
};
if (EnableTempStoreMemory)
{
queries.Add("PRAGMA temp_store = memory");
}
//var cacheSize = CacheSize;
//if (cacheSize.HasValue)
//{
//}
////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))
{
queries.Add("PRAGMA journal_mode=WAL");
using (WriteLock.Write())
{ {
db.ExecuteAll(string.Join(";", queries.ToArray())); _versionLogged = true;
Logger.Info("Sqlite version: " + SQLite3.Version);
Logger.Info("Sqlite compiler options: " + string.Join(",", SQLite3.CompilerOptions.ToArray()));
} }
}
else*/
if (queries.Count > 0)
{
db.ExecuteAll(string.Join(";", queries.ToArray()));
}
return db; ConnectionFlags connectionFlags;
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 (EnableSingleConnection)
{
connectionFlags |= ConnectionFlags.PrivateCache;
}
else
{
connectionFlags |= ConnectionFlags.SharedCached;
}
connectionFlags |= ConnectionFlags.NoMutex;
var db = SQLite3.Open(DbFilePath, connectionFlags, null);
if (string.IsNullOrWhiteSpace(_defaultWal))
{
_defaultWal = db.Query("PRAGMA journal_mode").SelectScalarString().First();
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"
};
if (CacheSize.HasValue)
{
queries.Add("PRAGMA cache_size=-" + CacheSize.Value.ToString(CultureInfo.InvariantCulture));
}
if (EnableTempStoreMemory)
{
queries.Add("PRAGMA temp_store = memory");
}
//var cacheSize = CacheSize;
//if (cacheSize.HasValue)
//{
//}
////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))
{
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;
}
}
public IStatement PrepareStatement(ManagedConnection connection, string sql)
{
return connection.PrepareStatement(sql);
}
public IStatement PrepareStatementSafe(ManagedConnection connection, string sql)
{
return connection.PrepareStatement(sql);
} }
public IStatement PrepareStatement(IDatabaseConnection connection, string sql) public IStatement PrepareStatement(IDatabaseConnection connection, string sql)
@ -143,22 +187,23 @@ namespace Emby.Server.Implementations.Data
return connection.PrepareStatement(sql); 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> var queries = new List<string>
{ {
"PRAGMA journal_mode=WAL", "PRAGMA journal_mode=WAL",
"PRAGMA page_size=4096", "PRAGMA page_size=4096",
"PRAGMA synchronous=Normal"
}; };
if (EnableTempStoreMemory) if (EnableTempStoreMemory)
@ -171,6 +216,7 @@ namespace Emby.Server.Implementations.Data
} }
db.ExecuteAll(string.Join(";", queries.ToArray())); db.ExecuteAll(string.Join(";", queries.ToArray()));
Logger.Info("PRAGMA synchronous=" + db.Query("PRAGMA synchronous").SelectScalarString().First());
} }
protected virtual bool EnableTempStoreMemory protected virtual bool EnableTempStoreMemory
@ -238,6 +284,12 @@ namespace Emby.Server.Implementations.Data
{ {
using (WriteLock.Write()) using (WriteLock.Write())
{ {
if (_connection != null)
{
_connection.Close();
_connection = null;
}
CloseConnection(); CloseConnection();
} }
} }
@ -332,7 +384,7 @@ namespace Emby.Server.Implementations.Data
//{ //{
// return new DummyToken(); // return new DummyToken();
//} //}
return new ReadLockToken(obj); return new WriteLockToken(obj);
} }
public static IDisposable Write(this ReaderWriterLockSlim obj) public static IDisposable Write(this ReaderWriterLockSlim obj)
{ {

View file

@ -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); var commandText = string.Format("attach @path as {0};", alias);

View file

@ -105,13 +105,7 @@ namespace Emby.Server.Implementations.Data
{ {
get get
{ {
var cacheSize = _config.Configuration.SqliteCacheSize; return 20000;
if (cacheSize <= 0)
{
cacheSize = Math.Min(Environment.ProcessorCount * 50000, 100000);
}
return 0 - cacheSize;
} }
} }
@ -328,6 +322,8 @@ namespace Emby.Server.Implementations.Data
"drop table if exists Images", "drop table if exists Images",
"drop index if exists idx_Images", "drop index if exists idx_Images",
"drop index if exists idx_TypeSeriesPresentationUniqueKey", "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_PathTypedBaseItems on TypedBaseItems(Path)",
"create index if not exists idx_ParentIdTypedBaseItems on TypedBaseItems(ParentId)", "create index if not exists idx_ParentIdTypedBaseItems on TypedBaseItems(ParentId)",
@ -343,8 +339,9 @@ namespace Emby.Server.Implementations.Data
// series // series
"create index if not exists idx_TypeSeriesPresentationUniqueKey1 on TypedBaseItems(Type,SeriesPresentationUniqueKey,PresentationUniqueKey,SortName)", "create index if not exists idx_TypeSeriesPresentationUniqueKey1 on TypedBaseItems(Type,SeriesPresentationUniqueKey,PresentationUniqueKey,SortName)",
// series next up // series counts
"create index if not exists idx_SeriesPresentationUniqueKey on TypedBaseItems(SeriesPresentationUniqueKey)", // seriesdateplayed sort order
"create index if not exists idx_TypeSeriesPresentationUniqueKey3 on TypedBaseItems(SeriesPresentationUniqueKey,Type,IsFolder,IsVirtualItem)",
// live tv programs // live tv programs
"create index if not exists idx_TypeTopParentIdStartDate on TypedBaseItems(Type,TopParentId,StartDate)", "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); //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) private void OnShrinkMemoryTimerCallback(object state)
@ -698,12 +695,12 @@ namespace Emby.Server.Implementations.Data
{ {
var requiresReset = false; var requiresReset = false;
var statements = PrepareAll(db, string.Join(";", new string[] var statements = PrepareAllSafe(db, new string[]
{ {
GetSaveItemCommandText(), GetSaveItemCommandText(),
"delete from AncestorIds where ItemId=@ItemId", "delete from AncestorIds where ItemId=@ItemId",
"insert into AncestorIds (ItemId, AncestorId, AncestorIdText) values (@ItemId, @AncestorId, @AncestorIdText)" "insert into AncestorIds (ItemId, AncestorId, AncestorIdText) values (@ItemId, @AncestorId, @AncestorIdText)"
})).ToList(); }).ToList();
using (var saveItemStatement = statements[0]) using (var saveItemStatement = statements[0])
{ {
@ -1264,9 +1261,10 @@ namespace Emby.Server.Implementations.Data
return GetItem(row); return GetItem(row);
} }
} }
return null;
} }
} }
return null;
} }
private BaseItem GetItem(IReadOnlyList<IResultSetValue> reader) private BaseItem GetItem(IReadOnlyList<IResultSetValue> reader)
@ -2079,12 +2077,12 @@ namespace Emby.Server.Implementations.Data
throw new ArgumentNullException("id"); throw new ArgumentNullException("id");
} }
var list = new List<ChapterInfo>();
using (WriteLock.Read()) using (WriteLock.Read())
{ {
using (var connection = CreateConnection(true)) 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")) using (var statement = PrepareStatementSafe(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc"))
{ {
statement.TryBind("@ItemId", id); statement.TryBind("@ItemId", id);
@ -2094,10 +2092,10 @@ namespace Emby.Server.Implementations.Data
list.Add(GetChapter(row)); list.Add(GetChapter(row));
} }
} }
return list;
} }
} }
return list;
} }
/// <summary> /// <summary>
@ -2240,7 +2238,7 @@ namespace Emby.Server.Implementations.Data
if (query.SimilarTo != null && query.User != null) if (query.SimilarTo != null && query.User != null)
{ {
return true; //return true;
} }
var sortingFields = query.SortBy.ToList(); 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) < 10 Then 2 Else 0 End )");
builder.Append("+(Select Case When Abs(COALESCE(ProductionYear, 0) - @ItemProductionYear) < 5 Then 2 Else 0 End )"); builder.Append("+(Select Case When Abs(COALESCE(ProductionYear, 0) - @ItemProductionYear) < 5 Then 2 Else 0 End )");
//// genres //// genres, tags
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)"); 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)");
//// tags //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=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)");
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)"); //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); //commandText += GetGroupBy(query);
int count = 0;
using (WriteLock.Read()) using (WriteLock.Read())
{ {
using (var connection = CreateConnection(true)) using (var connection = CreateConnection(true))
@ -2493,14 +2484,13 @@ namespace Emby.Server.Implementations.Data
// Running this again will bind the params // Running this again will bind the params
GetWhereClauses(query, statement); 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) public List<BaseItem> GetItemList(InternalItemsQuery query)
@ -2516,8 +2506,6 @@ namespace Emby.Server.Implementations.Data
var now = DateTime.UtcNow; 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 // Hack for right now since we currently don't support filtering out these duplicates within a query
if (query.Limit.HasValue && query.EnableGroupByMetadataKey) if (query.Limit.HasValue && query.EnableGroupByMetadataKey)
{ {
@ -2558,53 +2546,59 @@ namespace Emby.Server.Implementations.Data
{ {
using (var connection = CreateConnection(true)) 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))
}
BindSimilarParams(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)
{ {
list.Add(item); statement.TryBind("@UserId", query.User.Id);
}
BindSimilarParams(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)
{
list.Add(item);
}
} }
} }
}
// 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);
if (newList.Count >= limit)
{
break;
}
}
list = newList;
}
LogQueryTime("GetItemList", commandText, now);
return list;
}, ReadTransactionMode);
} }
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>();
foreach (var item in list)
{
AddItem(newList, item);
if (newList.Count >= limit)
{
break;
}
}
list = newList;
}
return list;
} }
private void AddItem(List<BaseItem> items, BaseItem newItem) private void AddItem(List<BaseItem> items, BaseItem newItem)
@ -2642,7 +2636,7 @@ namespace Emby.Server.Implementations.Data
var slowThreshold = 1000; var slowThreshold = 1000;
#if DEBUG #if DEBUG
slowThreshold = 50; slowThreshold = 2;
#endif #endif
if (elapsed >= slowThreshold) 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 isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0;
var statementTexts = new List<string>(); var statementTexts = new List<string>();
@ -2753,9 +2746,10 @@ namespace Emby.Server.Implementations.Data
{ {
using (var connection = CreateConnection(true)) 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(); .ToList();
if (!isReturningZeroItems) if (!isReturningZeroItems)
@ -2801,12 +2795,12 @@ namespace Emby.Server.Implementations.Data
} }
} }
LogQueryTime("GetItems", commandText, now);
result.Items = list.ToArray();
return result;
}, ReadTransactionMode); }, ReadTransactionMode);
LogQueryTime("GetItems", commandText, now);
result.Items = list.ToArray();
return result;
} }
} }
} }
@ -2967,12 +2961,12 @@ namespace Emby.Server.Implementations.Data
} }
} }
var list = new List<Guid>();
using (WriteLock.Read()) using (WriteLock.Read())
{ {
using (var connection = CreateConnection(true)) using (var connection = CreateConnection(true))
{ {
var list = new List<Guid>();
using (var statement = PrepareStatementSafe(connection, commandText)) using (var statement = PrepareStatementSafe(connection, commandText))
{ {
if (EnableJoinUserData(query)) if (EnableJoinUserData(query))
@ -2990,11 +2984,11 @@ namespace Emby.Server.Implementations.Data
list.Add(row[0].ReadGuid()); list.Add(row[0].ReadGuid());
} }
} }
LogQueryTime("GetItemList", commandText, now);
return list;
} }
LogQueryTime("GetItemList", commandText, now);
return list;
} }
} }
@ -3158,11 +3152,11 @@ namespace Emby.Server.Implementations.Data
{ {
using (var connection = CreateConnection(true)) using (var connection = CreateConnection(true))
{ {
var result = new QueryResult<Guid>(); return connection.RunInTransaction(db =>
connection.RunInTransaction(db =>
{ {
var statements = PrepareAllSafe(db, string.Join(";", statementTexts.ToArray())) var result = new QueryResult<Guid>();
var statements = PrepareAllSafe(db, statementTexts)
.ToList(); .ToList();
if (!isReturningZeroItems) if (!isReturningZeroItems)
@ -3204,12 +3198,12 @@ namespace Emby.Server.Implementations.Data
} }
} }
LogQueryTime("GetItemIds", commandText, now);
result.Items = list.ToArray();
return result;
}, ReadTransactionMode); }, ReadTransactionMode);
LogQueryTime("GetItemIds", commandText, now);
result.Items = list.ToArray();
return result;
} }
} }
} }
@ -4658,26 +4652,23 @@ namespace Emby.Server.Implementations.Data
commandText += " order by ListOrder"; commandText += " order by ListOrder";
var list = new List<string>();
using (WriteLock.Read()) using (WriteLock.Read())
{ {
using (var connection = CreateConnection(true)) 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()) foreach (var row in statement.ExecuteQuery())
{ {
list.Add(row.GetString(0)); list.Add(row.GetString(0));
}
} }
}, ReadTransactionMode); }
return list;
} }
return list;
} }
} }
@ -4701,29 +4692,26 @@ namespace Emby.Server.Implementations.Data
commandText += " order by ListOrder"; commandText += " order by ListOrder";
var list = new List<PersonInfo>();
using (WriteLock.Read()) using (WriteLock.Read())
{ {
using (var connection = CreateConnection(true)) using (var connection = CreateConnection(true))
{ {
connection.RunInTransaction(db => var list = new List<PersonInfo>();
{
using (var statement = PrepareStatementSafe(db, commandText))
{
// Run this again to bind the params
GetPeopleWhereClauses(query, statement);
foreach (var row in statement.ExecuteQuery()) using (var statement = PrepareStatementSafe(connection, commandText))
{ {
list.Add(GetPerson(row)); // Run this again to bind the params
} GetPeopleWhereClauses(query, statement);
foreach (var row in statement.ExecuteQuery())
{
list.Add(GetPerson(row));
} }
}, ReadTransactionMode); }
return list;
} }
} }
return list;
} }
private List<string> GetPeopleWhereClauses(InternalPeopleQuery query, IStatement statement) private List<string> GetPeopleWhereClauses(InternalPeopleQuery query, IStatement statement)
@ -4904,8 +4892,6 @@ namespace Emby.Server.Implementations.Data
("Type=" + itemValueTypes[0].ToString(CultureInfo.InvariantCulture)) : ("Type=" + itemValueTypes[0].ToString(CultureInfo.InvariantCulture)) :
("Type in (" + string.Join(",", itemValueTypes.Select(i => i.ToString(CultureInfo.InvariantCulture)).ToArray()) + ")"); ("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; var commandText = "Select Value From ItemValues where " + typeClause;
if (withItemTypes.Count > 0) if (withItemTypes.Count > 0)
@ -4925,24 +4911,24 @@ namespace Emby.Server.Implementations.Data
{ {
using (var connection = CreateConnection(true)) 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) 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 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>(); var statementTexts = new List<string>();
if (!isReturningZeroItems) if (!isReturningZeroItems)
{ {
@ -5107,9 +5090,13 @@ namespace Emby.Server.Implementations.Data
{ {
using (var connection = CreateConnection(true)) 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) if (!isReturningZeroItems)
{ {
@ -5172,17 +5159,18 @@ namespace Emby.Server.Implementations.Data
LogQueryTime("GetItemValues", commandText, now); LogQueryTime("GetItemValues", commandText, now);
} }
} }
if (result.TotalRecordCount == 0)
{
result.TotalRecordCount = list.Count;
}
result.Items = list.ToArray();
return result;
}, ReadTransactionMode); }, 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) private ItemCounts GetItemCounts(IReadOnlyList<IResultSetValue> reader, int countStartColumn, List<string> typesToCount)
@ -5395,8 +5383,6 @@ namespace Emby.Server.Implementations.Data
throw new ArgumentNullException("query"); throw new ArgumentNullException("query");
} }
var list = new List<MediaStream>();
var cmdText = "select " + string.Join(",", _mediaStreamSaveColumns) + " from mediastreams where"; var cmdText = "select " + string.Join(",", _mediaStreamSaveColumns) + " from mediastreams where";
cmdText += " ItemId=@ItemId"; cmdText += " ItemId=@ItemId";
@ -5417,32 +5403,31 @@ namespace Emby.Server.Implementations.Data
{ {
using (var connection = CreateConnection(true)) 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());
if (query.Type.HasValue)
{ {
statement.TryBind("@ItemId", query.ItemId.ToGuidParamValue()); 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);
}
foreach (var row in statement.ExecuteQuery())
{
list.Add(GetMediaStream(row));
}
} }
}, ReadTransactionMode);
if (query.Index.HasValue)
{
statement.TryBind("@StreamIndex", query.Index.Value);
}
foreach (var row in statement.ExecuteQuery())
{
list.Add(GetMediaStream(row));
}
}
return list;
} }
} }
return list;
} }
public async Task SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken) public async Task SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken)

View file

@ -42,8 +42,10 @@ namespace Emby.Server.Implementations.Data
/// Opens the connection to the database /// Opens the connection to the database
/// </summary> /// </summary>
/// <returns>Task.</returns> /// <returns>Task.</returns>
public void Initialize(ReaderWriterLockSlim writeLock) public void Initialize(ReaderWriterLockSlim writeLock, ManagedConnection managedConnection)
{ {
_connection = managedConnection;
WriteLock.Dispose(); WriteLock.Dispose();
WriteLock = writeLock; 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)) if (!_fileSystem.FileExists(_importFile))
{ {
@ -117,7 +119,7 @@ namespace Emby.Server.Implementations.Data
}, TransactionMode); }, TransactionMode);
} }
private void ImportUserData(IDatabaseConnection connection, string file) private void ImportUserData(ManagedConnection connection, string file)
{ {
SqliteExtensions.Attach(connection, file, "UserDataBackup"); SqliteExtensions.Attach(connection, file, "UserDataBackup");
@ -300,24 +302,18 @@ namespace Emby.Server.Implementations.Data
{ {
using (var connection = CreateConnection(true)) using (var connection = CreateConnection(true))
{ {
UserItemData result = null; using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key =@Key and userId=@UserId"))
connection.RunInTransaction(db =>
{ {
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()); return ReadRow(row);
statement.TryBind("@Key", key);
foreach (var row in statement.ExecuteQuery())
{
result = ReadRow(row);
break;
}
} }
}, ReadTransactionMode); }
return result; return null;
} }
} }
} }

View file

@ -459,12 +459,21 @@ namespace Emby.Server.Implementations.Dto
if (dtoOptions.EnableUserData) 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) 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)) if (fields.Contains(ItemFields.CumulativeRunTimeTicks))
@ -1151,28 +1160,29 @@ namespace Emby.Server.Implementations.Dto
{ {
dto.Artists = hasArtist.Artists; dto.Artists = hasArtist.Artists;
var artistItems = _libraryManager.GetArtists(new InternalItemsQuery //var artistItems = _libraryManager.GetArtists(new InternalItemsQuery
{ //{
EnableTotalRecordCount = false, // EnableTotalRecordCount = false,
ItemIds = new[] { item.Id.ToString("N") } // ItemIds = new[] { item.Id.ToString("N") }
}); //});
dto.ArtistItems = artistItems.Items //dto.ArtistItems = artistItems.Items
.Select(i => // .Select(i =>
{ // {
var artist = i.Item1; // var artist = i.Item1;
return new NameIdPair // return new NameIdPair
{ // {
Name = artist.Name, // Name = artist.Name,
Id = artist.Id.ToString("N") // Id = artist.Id.ToString("N")
}; // };
}) // })
.ToList(); // .ToList();
// Include artists that are not in the database yet, e.g., just added via metadata editor // 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 dto.ArtistItems.AddRange(hasArtist.Artists
.Except(foundArtists, new DistinctNameComparer()) //.Except(foundArtists, new DistinctNameComparer())
.Select(i => .Select(i =>
{ {
// This should not be necessary but we're seeing some cases of it // 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(); dto.AlbumArtist = hasAlbumArtist.AlbumArtists.FirstOrDefault();
var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery //var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery
{ //{
EnableTotalRecordCount = false, // EnableTotalRecordCount = false,
ItemIds = new[] { item.Id.ToString("N") } // ItemIds = new[] { item.Id.ToString("N") }
}); //});
dto.AlbumArtists = artistItems.Items //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 => .Select(i =>
{ {
var artist = i.Item1; // This should not be necessary but we're seeing some cases of it
return new NameIdPair if (string.IsNullOrWhiteSpace(i))
{ {
Name = artist.Name, return null;
Id = artist.Id.ToString("N") }
};
}) var artist = _libraryManager.GetArtist(i);
.ToList(); if (artist != null)
{
return new NameIdPair
{
Name = artist.Name,
Id = artist.Id.ToString("N")
};
}
return null;
}).Where(i => i != null));
} }
// Add video info // Add video info

View file

@ -51,6 +51,7 @@
<Compile Include="Connect\ConnectManager.cs" /> <Compile Include="Connect\ConnectManager.cs" />
<Compile Include="Connect\Responses.cs" /> <Compile Include="Connect\Responses.cs" />
<Compile Include="Connect\Validator.cs" /> <Compile Include="Connect\Validator.cs" />
<Compile Include="Data\ManagedConnection.cs" />
<Compile Include="Data\SqliteDisplayPreferencesRepository.cs" /> <Compile Include="Data\SqliteDisplayPreferencesRepository.cs" />
<Compile Include="Data\SqliteFileOrganizationRepository.cs" /> <Compile Include="Data\SqliteFileOrganizationRepository.cs" />
<Compile Include="Data\SqliteItemRepository.cs" /> <Compile Include="Data\SqliteItemRepository.cs" />
@ -180,6 +181,7 @@
<Compile Include="Localization\LocalizationManager.cs" /> <Compile Include="Localization\LocalizationManager.cs" />
<Compile Include="MediaEncoder\EncodingManager.cs" /> <Compile Include="MediaEncoder\EncodingManager.cs" />
<Compile Include="Migrations\IVersionMigration.cs" /> <Compile Include="Migrations\IVersionMigration.cs" />
<Compile Include="Migrations\LibraryScanMigration.cs" />
<Compile Include="Migrations\UpdateLevelMigration.cs" /> <Compile Include="Migrations\UpdateLevelMigration.cs" />
<Compile Include="News\NewsEntryPoint.cs" /> <Compile Include="News\NewsEntryPoint.cs" />
<Compile Include="News\NewsService.cs" /> <Compile Include="News\NewsService.cs" />

View file

@ -519,6 +519,12 @@ namespace Emby.Server.Implementations.FileOrganization
private void PerformFileSorting(TvFileOrganizationOptions options, FileOrganizationResult result) 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); _libraryMonitor.ReportFileSystemChangeBeginning(result.TargetPath);
_fileSystem.CreateDirectory(Path.GetDirectoryName(result.TargetPath)); _fileSystem.CreateDirectory(Path.GetDirectoryName(result.TargetPath));

View file

@ -76,7 +76,8 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
private void ProcessContext(HttpListenerContext context) 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) private Task InitTask(HttpListenerContext context)

View file

@ -817,7 +817,31 @@ namespace Emby.Server.Implementations.Library
return _userRootFolder; 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) public BaseItem FindByPath(string path, bool? isFolder)
{ {
// If this returns multiple items it could be tricky figuring out which one is correct. // 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 // 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[] { }; query.AncestorIds = new string[] { };
} }
} }
@ -1489,7 +1513,7 @@ namespace Emby.Server.Implementations.Library
})) }))
{ {
// Optimize by querying against top level views // 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 else
{ {
@ -1515,11 +1539,11 @@ namespace Emby.Server.Implementations.Library
}, CancellationToken.None).Result.ToList(); }, 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; var view = item as UserView;
@ -1527,7 +1551,7 @@ namespace Emby.Server.Implementations.Library
{ {
if (string.Equals(view.ViewType, CollectionType.LiveTv)) if (string.Equals(view.ViewType, CollectionType.LiveTv))
{ {
return new[] { view }; return new[] { view.Id };
} }
if (string.Equals(view.ViewType, CollectionType.Channels)) if (string.Equals(view.ViewType, CollectionType.Channels))
{ {
@ -1537,7 +1561,7 @@ namespace Emby.Server.Implementations.Library
}, CancellationToken.None).Result; }, CancellationToken.None).Result;
return channelResult.Items; return channelResult.Items.Select(i => i.Id);
} }
// Translate view into folders // Translate view into folders
@ -1546,18 +1570,18 @@ namespace Emby.Server.Implementations.Library
var displayParent = GetItemById(view.DisplayParentId); var displayParent = GetItemById(view.DisplayParentId);
if (displayParent != null) if (displayParent != null)
{ {
return GetTopParentsForQuery(displayParent, user); return GetTopParentIdsForQuery(displayParent, user);
} }
return new BaseItem[] { }; return new Guid[] { };
} }
if (view.ParentId != Guid.Empty) if (view.ParentId != Guid.Empty)
{ {
var displayParent = GetItemById(view.ParentId); var displayParent = GetItemById(view.ParentId);
if (displayParent != null) if (displayParent != null)
{ {
return GetTopParentsForQuery(displayParent, user); return GetTopParentIdsForQuery(displayParent, user);
} }
return new BaseItem[] { }; return new Guid[] { };
} }
// Handle grouping // Handle grouping
@ -1568,23 +1592,23 @@ namespace Emby.Server.Implementations.Library
.OfType<CollectionFolder>() .OfType<CollectionFolder>()
.Where(i => string.IsNullOrWhiteSpace(i.CollectionType) || string.Equals(i.CollectionType, view.ViewType, StringComparison.OrdinalIgnoreCase)) .Where(i => string.IsNullOrWhiteSpace(i.CollectionType) || string.Equals(i.CollectionType, view.ViewType, StringComparison.OrdinalIgnoreCase))
.Where(i => user.IsFolderGrouped(i.Id)) .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; var collectionFolder = item as CollectionFolder;
if (collectionFolder != null) if (collectionFolder != null)
{ {
return collectionFolder.GetPhysicalParents(); return collectionFolder.PhysicalFolderIds;
} }
var topParent = item.GetTopParent(); var topParent = item.GetTopParent();
if (topParent != null) if (topParent != null)
{ {
return new[] { topParent }; return new[] { topParent.Id };
} }
return new BaseItem[] { }; return new Guid[] { };
} }
/// <summary> /// <summary>

View file

@ -12,6 +12,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Library namespace Emby.Server.Implementations.Library
{ {
@ -186,16 +187,16 @@ namespace Emby.Server.Implementations.Library
var userData = GetUserData(user.Id, item); var userData = GetUserData(user.Id, item);
var dto = GetUserItemDataDto(userData); 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; 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 userData = GetUserData(user.Id, item);
var dto = GetUserItemDataDto(userData); 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; return dto;
} }

View file

@ -328,15 +328,35 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
} }
await UpdateTimersForSeriesTimer(epgData, timer, true).ConfigureAwait(false); await UpdateTimersForSeriesTimer(epgData, timer, true).ConfigureAwait(false);
} }
}
public async Task RefreshTimers(CancellationToken cancellationToken, IProgress<double> progress)
{
var timers = await GetTimersAsync(cancellationToken).ConfigureAwait(false); 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)) if (DateTime.UtcNow > timer.EndDate && !_activeRecordings.ContainsKey(timer.Id))
{ {
OnTimerOutOfDate(timer); 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);
} }
} }

View file

@ -41,6 +41,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public static void CopyProgramInfoToTimerInfo(ProgramInfo programInfo, TimerInfo timerInfo) 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.SeasonNumber = programInfo.SeasonNumber;
timerInfo.EpisodeNumber = programInfo.EpisodeNumber; timerInfo.EpisodeNumber = programInfo.EpisodeNumber;
timerInfo.IsMovie = programInfo.IsMovie; timerInfo.IsMovie = programInfo.IsMovie;
@ -54,6 +59,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
timerInfo.HomePageUrl = programInfo.HomePageUrl; timerInfo.HomePageUrl = programInfo.HomePageUrl;
timerInfo.CommunityRating = programInfo.CommunityRating; timerInfo.CommunityRating = programInfo.CommunityRating;
timerInfo.Overview = programInfo.Overview;
timerInfo.ShortOverview = programInfo.ShortOverview; timerInfo.ShortOverview = programInfo.ShortOverview;
timerInfo.OfficialRating = programInfo.OfficialRating; timerInfo.OfficialRating = programInfo.OfficialRating;
timerInfo.IsRepeat = programInfo.IsRepeat; timerInfo.IsRepeat = programInfo.IsRepeat;

View file

@ -1231,6 +1231,7 @@ namespace Emby.Server.Implementations.LiveTv
if (coreService != null) if (coreService != null)
{ {
await coreService.RefreshSeriesTimers(cancellationToken, new Progress<double>()).ConfigureAwait(false); 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 // Load these now which will prefetch metadata

View file

@ -65,9 +65,9 @@ namespace Emby.Server.Implementations.Notifications
var whereClause = " where " + string.Join(" And ", clauses.ToArray()); 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(); 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(); 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")) 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(); cancellationToken.ThrowIfCancellationRequested();
using (var connection = CreateConnection()) lock (WriteLock)
{ {
lock (WriteLock) using (var connection = CreateConnection())
{ {
connection.RunInTransaction(conn => connection.RunInTransaction(conn =>
{ {
@ -286,9 +286,9 @@ namespace Emby.Server.Implementations.Notifications
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
using (var connection = CreateConnection()) using (WriteLock.Write())
{ {
lock (WriteLock) using (var connection = CreateConnection())
{ {
connection.RunInTransaction(conn => connection.RunInTransaction(conn =>
{ {
@ -308,9 +308,9 @@ namespace Emby.Server.Implementations.Notifications
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
using (var connection = CreateConnection()) using (WriteLock.Write())
{ {
lock (WriteLock) using (var connection = CreateConnection())
{ {
connection.RunInTransaction(conn => connection.RunInTransaction(conn =>
{ {

View file

@ -206,15 +206,15 @@ namespace Emby.Server.Implementations.Security
{ {
using (var connection = CreateConnection(true)) using (var connection = CreateConnection(true))
{ {
var result = new QueryResult<AuthenticationInfo>(); return connection.RunInTransaction(db =>
connection.RunInTransaction(db =>
{ {
var result = new QueryResult<AuthenticationInfo>();
var statementTexts = new List<string>(); var statementTexts = new List<string>();
statementTexts.Add(commandText); statementTexts.Add(commandText);
statementTexts.Add("select count (Id) from AccessTokens" + whereTextWithoutPaging); statementTexts.Add("select count (Id) from AccessTokens" + whereTextWithoutPaging);
var statements = PrepareAllSafe(db, string.Join(";", statementTexts.ToArray())) var statements = PrepareAllSafe(db, statementTexts)
.ToList(); .ToList();
using (var statement = statements[0]) 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(); }, ReadTransactionMode);
return result;
} }
} }
} }

View file

@ -143,7 +143,7 @@ namespace Emby.Server.Implementations.TV
// If viewing all next up for all series, remove first episodes // If viewing all next up for all series, remove first episodes
// But if that returns empty, keep those first episodes (avoid completely empty view) // 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; var isFirstItemAFirstEpisode = true;
return allNextUp return allNextUp

View file

@ -121,7 +121,9 @@ namespace MediaBrowser.Api
{ {
var options = new DtoOptions(); var options = new DtoOptions();
options.DeviceId = authContext.GetAuthorizationInfo(Request).DeviceId; var authInfo = authContext.GetAuthorizationInfo(Request);
options.DeviceId = authInfo.DeviceId;
var hasFields = request as IHasItemFields; var hasFields = request as IHasItemFields;
if (hasFields != null) if (hasFields != null)
@ -129,6 +131,34 @@ namespace MediaBrowser.Api
options.Fields = hasFields.GetItemFields().ToList(); 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; var hasDtoOptions = request as IHasDtoOptions;
if (hasDtoOptions != null) if (hasDtoOptions != null)
{ {

View file

@ -14,8 +14,6 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.IO;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services; 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")] [Route("/Items/RemoteSearch/Image", "GET", Summary = "Gets a remote image")]
public class GetRemoteSearchImage public class GetRemoteSearchImage
{ {
@ -147,6 +151,13 @@ namespace MediaBrowser.Api
return ToOptimizedResult(result); 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) public async Task<object> Post(GetMovieRemoteSearchResults request)
{ {
var result = await _providerManager.GetRemoteSearchResults<Movie, MovieInfo>(request, CancellationToken.None).ConfigureAwait(false); var result = await _providerManager.GetRemoteSearchResults<Movie, MovieInfo>(request, CancellationToken.None).ConfigureAwait(false);

View file

@ -2358,7 +2358,8 @@ namespace MediaBrowser.Api.Playback
state.TargetVideoStreamCount, state.TargetVideoStreamCount,
state.TargetAudioStreamCount, state.TargetAudioStreamCount,
state.TargetVideoCodecTag, state.TargetVideoCodecTag,
state.IsTargetAVC); state.IsTargetAVC,
state.AllAudioCodecs);
if (mediaProfile != null) if (mediaProfile != null)
{ {
@ -2580,7 +2581,8 @@ namespace MediaBrowser.Api.Playback
state.TargetVideoStreamCount, state.TargetVideoStreamCount,
state.TargetAudioStreamCount, state.TargetAudioStreamCount,
state.TargetVideoCodecTag, state.TargetVideoCodecTag,
state.IsTargetAVC state.IsTargetAVC,
state.AllAudioCodecs
).FirstOrDefault() ?? string.Empty; ).FirstOrDefault() ?? string.Empty;
} }

View file

@ -11,6 +11,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq;
using System.Threading; using System.Threading;
namespace MediaBrowser.Api.Playback namespace MediaBrowser.Api.Playback
@ -244,6 +245,17 @@ namespace MediaBrowser.Api.Playback
public int? OutputAudioBitrate; public int? OutputAudioBitrate;
public int? OutputVideoBitrate; 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 public string ActualOutputVideoCodec
{ {
get get

View file

@ -30,6 +30,7 @@ using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Providers; using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
@ -2191,7 +2192,7 @@ namespace MediaBrowser.Controller.Entities
return path; 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) if (RunTimeTicks.HasValue)
{ {

View file

@ -27,6 +27,7 @@ namespace MediaBrowser.Controller.Entities
public CollectionFolder() public CollectionFolder()
{ {
PhysicalLocationsList = new List<string>(); PhysicalLocationsList = new List<string>();
PhysicalFolderIds = new List<Guid>();
} }
[IgnoreDataMember] [IgnoreDataMember]
@ -153,6 +154,7 @@ namespace MediaBrowser.Controller.Entities
} }
public List<string> PhysicalLocationsList { get; set; } public List<string> PhysicalLocationsList { get; set; }
public List<Guid> PhysicalFolderIds { get; set; }
protected override IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService) 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; return changed;
} }
@ -186,6 +200,31 @@ namespace MediaBrowser.Controller.Entities
return changed; 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) internal override bool IsValidFromResolver(BaseItem newItem)
{ {
var newCollectionFolder = newItem as CollectionFolder; var newCollectionFolder = newItem as CollectionFolder;
@ -260,26 +299,6 @@ namespace MediaBrowser.Controller.Entities
return Task.FromResult(true); return Task.FromResult(true);
} }
/// <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> /// <summary>
/// Our children are actually just references to the ones in the physical root... /// Our children are actually just references to the ones in the physical root...
/// </summary> /// </summary>
@ -292,11 +311,16 @@ namespace MediaBrowser.Controller.Entities
private IEnumerable<BaseItem> GetActualChildren() 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 var rootChildren = LibraryManager.RootFolder.Children
.OfType<Folder>() .OfType<Folder>()
.ToList(); .ToList();

View file

@ -1222,7 +1222,7 @@ namespace MediaBrowser.Controller.Entities
/// Refreshes the linked children. /// Refreshes the linked children.
/// </summary> /// </summary>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> /// <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 currentManualLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Manual).ToList();
var currentShortcutLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut).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) if (!SupportsUserDataFromChildren)
{ {
return; return;
} }
var recursiveItemCount = GetRecursiveChildCount(user);
if (itemDto != null) 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, Recursive = true,
IsFolder = false, IsFolder = false,
@ -1435,21 +1436,24 @@ namespace MediaBrowser.Controller.Entities
Limit = 0, Limit = 0,
IsPlayed = false IsPlayed = false
}).ConfigureAwait(false) : new QueryResult<BaseItem>(); }).ConfigureAwait(false);
double unplayedCount = unplayedQueryResult.TotalRecordCount; double unplayedCount = unplayedQueryResult.TotalRecordCount;
var unplayedPercentage = (unplayedCount / recursiveItemCount) * 100;
dto.PlayedPercentage = 100 - unplayedPercentage;
dto.Played = dto.PlayedPercentage.Value >= 100;
dto.UnplayedItemCount = unplayedQueryResult.TotalRecordCount; dto.UnplayedItemCount = unplayedQueryResult.TotalRecordCount;
}
if (itemDto != null) if (itemDto != null && itemDto.RecursiveItemCount.HasValue)
{
if (this is Season || this is MusicAlbum)
{ {
itemDto.ChildCount = recursiveItemCount; if (itemDto.RecursiveItemCount.Value > 0)
{
var unplayedPercentage = (unplayedCount/itemDto.RecursiveItemCount.Value)*100;
dto.PlayedPercentage = 100 - unplayedPercentage;
dto.Played = dto.PlayedPercentage.Value >= 100;
}
}
else
{
dto.Played = (dto.UnplayedItemCount ?? 0) == 0;
} }
} }
} }

View file

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
@ -14,10 +15,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary> /// <summary>
/// Fills the user data dto values. /// Fills the user data dto values.
/// </summary> /// </summary>
/// <param name="dto">The dto.</param> Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List<ItemFields> fields);
/// <param name="userData">The user data.</param>
/// <param name="user">The user.</param>
Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user);
bool EnableRememberingTrackSelections { get; } bool EnableRememberingTrackSelections { get; }

View file

@ -62,6 +62,8 @@ namespace MediaBrowser.Controller.Library
/// <returns>BaseItem.</returns> /// <returns>BaseItem.</returns>
BaseItem FindByPath(string path, bool? isFolder); BaseItem FindByPath(string path, bool? isFolder);
Guid? FindIdByPath(string path, bool? isFolder);
/// <summary> /// <summary>
/// Gets the artist. /// Gets the artist.
/// </summary> /// </summary>

View file

@ -5,6 +5,7 @@ using MediaBrowser.Model.Entities;
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Library namespace MediaBrowser.Controller.Library
{ {
@ -37,12 +38,9 @@ namespace MediaBrowser.Controller.Library
/// <summary> /// <summary>
/// Gets the user data dto. /// Gets the user data dto.
/// </summary> /// </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, User user);
Task<UserItemDataDto> GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user); Task<UserItemDataDto> GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, List<ItemFields> fields);
/// <summary> /// <summary>
/// Get all user data for the given user /// Get all user data for the given user

View file

@ -11,6 +11,7 @@ using MediaBrowser.Model.Net;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; 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() private void DisposeIsoMount()
{ {
if (IsoMount != null) if (IsoMount != null)

View file

@ -846,7 +846,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
state.TargetVideoStreamCount, state.TargetVideoStreamCount,
state.TargetAudioStreamCount, state.TargetAudioStreamCount,
state.TargetVideoCodecTag, state.TargetVideoCodecTag,
state.IsTargetAVC); state.IsTargetAVC,
state.AllAudioCodecs);
if (mediaProfile != null) if (mediaProfile != null)
{ {

View file

@ -191,7 +191,6 @@ namespace MediaBrowser.Model.Configuration
public int SharingExpirationDays { get; set; } public int SharingExpirationDays { get; set; }
public int SchemaVersion { get; set; } public int SchemaVersion { get; set; }
public int SqliteCacheSize { get; set; }
public bool EnableAnonymousUsageReporting { get; set; } public bool EnableAnonymousUsageReporting { get; set; }
public bool EnableStandaloneMusicKeys { get; set; } public bool EnableStandaloneMusicKeys { get; set; }
@ -202,6 +201,7 @@ namespace MediaBrowser.Model.Configuration
public bool DisplayCollectionsView { get; set; } public bool DisplayCollectionsView { get; set; }
public string[] LocalNetworkAddresses { get; set; } public string[] LocalNetworkAddresses { get; set; }
public string[] CodecsUsed { get; set; } public string[] CodecsUsed { get; set; }
public string[] Migrations { get; set; }
public bool EnableChannelView { get; set; } public bool EnableChannelView { get; set; }
public bool EnableExternalContentInSuggestions { get; set; } public bool EnableExternalContentInSuggestions { get; set; }
public bool EnableSimpleArtistDetection { get; set; } public bool EnableSimpleArtistDetection { get; set; }
@ -214,7 +214,7 @@ namespace MediaBrowser.Model.Configuration
{ {
LocalNetworkAddresses = new string[] { }; LocalNetworkAddresses = new string[] { };
CodecsUsed = new string[] { }; CodecsUsed = new string[] { };
SqliteCacheSize = 0; Migrations = new string[] { };
ImageExtractionTimeoutMs = 0; ImageExtractionTimeoutMs = 0;
EnableLocalizedGuids = true; EnableLocalizedGuids = true;

View file

@ -1,7 +1,9 @@
using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using System; using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq;
namespace MediaBrowser.Model.Dlna namespace MediaBrowser.Model.Dlna
{ {
@ -22,12 +24,15 @@ namespace MediaBrowser.Model.Dlna
int? numVideoStreams, int? numVideoStreams,
int? numAudioStreams, int? numAudioStreams,
string videoCodecTag, string videoCodecTag,
bool? isAvc) bool? isAvc,
List<string> allAudioCodecs )
{ {
switch (condition.Property) switch (condition.Property)
{ {
case ProfileConditionValue.IsAnamorphic: case ProfileConditionValue.IsAnamorphic:
return IsConditionSatisfied(condition, isAnamorphic); return IsConditionSatisfied(condition, isAnamorphic);
case ProfileConditionValue.HasAudioCodec:
return IsHasAudioCodecConditionSatisfied(condition, allAudioCodecs);
case ProfileConditionValue.IsAvc: case ProfileConditionValue.IsAvc:
return IsConditionSatisfied(condition, isAvc); return IsConditionSatisfied(condition, isAvc);
case ProfileConditionValue.VideoFramerate: 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) private bool IsConditionSatisfied(ProfileCondition condition, bool? currentValue)
{ {
if (!currentValue.HasValue) if (!currentValue.HasValue)

View file

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Xml.Serialization; using System.Xml.Serialization;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Model.Dlna namespace MediaBrowser.Model.Dlna
{ {
@ -27,5 +28,12 @@ namespace MediaBrowser.Model.Dlna
} }
return list; return list;
} }
public bool ContainsContainer(string container)
{
List<string> containers = GetContainers();
return containers.Count == 0 || ListHelper.ContainsIgnoreCase(containers, container ?? string.Empty);
}
} }
} }

View file

@ -119,7 +119,8 @@ namespace MediaBrowser.Model.Dlna
int? numVideoStreams, int? numVideoStreams,
int? numAudioStreams, int? numAudioStreams,
string videoCodecTag, 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 // 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); string orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(runtimeTicks.HasValue, isDirectStream, transcodeSeekInfo);
@ -161,7 +162,8 @@ namespace MediaBrowser.Model.Dlna
numVideoStreams, numVideoStreams,
numAudioStreams, numAudioStreams,
videoCodecTag, videoCodecTag,
isAvc); isAvc,
allAudioCodecs);
List<string> orgPnValues = new List<string>(); List<string> orgPnValues = new List<string>();

View file

@ -297,7 +297,8 @@ namespace MediaBrowser.Model.Dlna
int? numVideoStreams, int? numVideoStreams,
int? numAudioStreams, int? numAudioStreams,
string videoCodecTag, string videoCodecTag,
bool? isAvc) bool? isAvc,
List<string> allAudioCodecs)
{ {
container = StringHelper.TrimStart(container ?? string.Empty, '.'); container = StringHelper.TrimStart(container ?? string.Empty, '.');
@ -331,7 +332,7 @@ namespace MediaBrowser.Model.Dlna
var anyOff = false; var anyOff = false;
foreach (ProfileCondition c in i.Conditions) 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; anyOff = true;
break; break;

View file

@ -21,6 +21,7 @@
NumVideoStreams = 17, NumVideoStreams = 17,
IsSecondaryAudio = 18, IsSecondaryAudio = 18,
VideoCodecTag = 19, VideoCodecTag = 19,
IsAvc = 20 IsAvc = 20,
HasAudioCodec = 21
} }
} }

View file

@ -7,6 +7,7 @@ using MediaBrowser.Model.Session;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq;
namespace MediaBrowser.Model.Dlna namespace MediaBrowser.Model.Dlna
{ {
@ -409,6 +410,9 @@ namespace MediaBrowser.Model.Dlna
audioStreamIndex = audioStream.Index; 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; 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 // 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) if (isEligibleForDirectPlay || isEligibleForDirectStream)
{ {
// See if it can be direct played // 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) if (directPlay != null)
{ {
@ -552,7 +556,7 @@ namespace MediaBrowser.Model.Dlna
int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio); int? numAudioStreams = item.GetStreamCount(MediaStreamType.Audio);
int? numVideoStreams = item.GetStreamCount(MediaStreamType.Video); 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); LogConditionFailure(options.Profile, "VideoCodecProfile", applyCondition, item);
applyConditions = false; applyConditions = false;
@ -653,7 +657,8 @@ namespace MediaBrowser.Model.Dlna
MediaStream videoStream, MediaStream videoStream,
MediaStream audioStream, MediaStream audioStream,
bool isEligibleForDirectPlay, bool isEligibleForDirectPlay,
bool isEligibleForDirectStream) bool isEligibleForDirectStream,
List<MediaStream> allMediaStreams)
{ {
DeviceProfile profile = options.Profile; DeviceProfile profile = options.Profile;
@ -701,7 +706,7 @@ namespace MediaBrowser.Model.Dlna
foreach (ContainerProfile i in profile.ContainerProfiles) foreach (ContainerProfile i in profile.ContainerProfiles)
{ {
if (i.Type == DlnaProfileType.Video && if (i.Type == DlnaProfileType.Video &&
ListHelper.ContainsIgnoreCase(i.GetContainers(), container)) i.ContainsContainer(container))
{ {
foreach (ProfileCondition c in i.Conditions) foreach (ProfileCondition c in i.Conditions)
{ {
@ -734,10 +739,12 @@ namespace MediaBrowser.Model.Dlna
int? numAudioStreams = mediaSource.GetStreamCount(MediaStreamType.Audio); int? numAudioStreams = mediaSource.GetStreamCount(MediaStreamType.Audio);
int? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video); 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 // Check container conditions
foreach (ProfileCondition i in 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); LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
@ -764,7 +771,7 @@ namespace MediaBrowser.Model.Dlna
bool applyConditions = true; bool applyConditions = true;
foreach (ProfileCondition applyCondition in i.ApplyConditions) 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); LogConditionFailure(profile, "VideoCodecProfile", applyCondition, mediaSource);
applyConditions = false; applyConditions = false;
@ -784,7 +791,7 @@ namespace MediaBrowser.Model.Dlna
foreach (ProfileCondition i in 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, "VideoCodecProfile", i, mediaSource); LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);

View file

@ -6,6 +6,7 @@ using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Session; using MediaBrowser.Model.Session;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace MediaBrowser.Model.Dlna 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> /// <summary>
/// Returns the video stream that will be used /// Returns the video stream that will be used
/// </summary> /// </summary>

View file

@ -171,6 +171,8 @@
/// </summary> /// </summary>
PrimaryImageAspectRatio, PrimaryImageAspectRatio,
RecursiveItemCount,
/// <summary> /// <summary>
/// The revenue /// The revenue
/// </summary> /// </summary>

View file

@ -307,9 +307,7 @@
<None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3594.ini" /> <None Include="LiveTv\TunerHosts\SatIp\ini\satellite\3594.ini" />
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup />
<Folder Include="Persistence\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.

View file

@ -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;
}
}
}

View file

@ -291,7 +291,7 @@ namespace Rssdp.Infrastructure
if (devices != null) if (devices != null)
{ {
var deviceList = devices.ToList(); 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) foreach (var device in deviceList)
{ {
@ -300,7 +300,7 @@ namespace Rssdp.Infrastructure
} }
else else
{ {
WriteTrace(String.Format("Sending 0 search responses.")); //WriteTrace(String.Format("Sending 0 search responses."));
} }
}); });
} }
@ -413,7 +413,7 @@ namespace Rssdp.Infrastructure
//DisposeRebroadcastTimer(); //DisposeRebroadcastTimer();
WriteTrace("Begin Sending Alive Notifications For All Devices"); //WriteTrace("Begin Sending Alive Notifications For All Devices");
_LastNotificationTime = DateTime.Now; _LastNotificationTime = DateTime.Now;
@ -430,7 +430,7 @@ namespace Rssdp.Infrastructure
SendAliveNotifications(device, true); SendAliveNotifications(device, true);
} }
WriteTrace("Completed Sending Alive Notifications For All Devices"); //WriteTrace("Completed Sending Alive Notifications For All Devices");
} }
catch (ObjectDisposedException ex) catch (ObjectDisposedException ex)
{ {

View file

@ -37,5 +37,10 @@
<ProjectReference Include="..\..\ServiceStack\ServiceStack.csproj" /> <ProjectReference Include="..\..\ServiceStack\ServiceStack.csproj" />
<ProjectReference Include="..\..\SocketHttpListener.Portable\SocketHttpListener.Portable.csproj" /> <ProjectReference Include="..\..\SocketHttpListener.Portable\SocketHttpListener.Portable.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Include="..\..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
</ItemGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project> </Project>

View file

@ -1,5 +1,5 @@
{ {
"version": "1.0.0-*", "version": "3.1.0-*",
"buildOptions": { "buildOptions": {
"emitEntryPoint": true "emitEntryPoint": true
}, },
@ -33,8 +33,26 @@
"win10-arm64": {}, "win10-arm64": {},
"osx.10.10-x64": {}, "osx.10.10-x64": {},
"osx.10.11-x64": {}, "osx.10.11-x64": {},
"osx.10.12-x64": {}, "osx.10.12-x64": ,
"ubuntu.14.04-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": { "frameworks": {