mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-05-22 16:46:54 +01:00
update server core project
This commit is contained in:
114
Emby.Server.Core/Data/BaseSqliteRepository.cs
Normal file
114
Emby.Server.Core/Data/BaseSqliteRepository.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Logging;
|
||||
|
||||
namespace Emby.Server.Core.Data
|
||||
{
|
||||
public abstract class BaseSqliteRepository : IDisposable
|
||||
{
|
||||
protected SemaphoreSlim WriteLock = new SemaphoreSlim(1, 1);
|
||||
protected readonly IDbConnector DbConnector;
|
||||
protected ILogger Logger;
|
||||
|
||||
protected string DbFilePath { get; set; }
|
||||
|
||||
protected BaseSqliteRepository(ILogManager logManager, IDbConnector dbConnector)
|
||||
{
|
||||
DbConnector = dbConnector;
|
||||
Logger = logManager.GetLogger(GetType().Name);
|
||||
}
|
||||
|
||||
protected virtual bool EnableConnectionPooling
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected virtual async Task<IDbConnection> CreateConnection(bool isReadOnly = false)
|
||||
{
|
||||
var connection = await DbConnector.Connect(DbFilePath, false, true).ConfigureAwait(false);
|
||||
|
||||
connection.RunQueries(new[]
|
||||
{
|
||||
"pragma temp_store = memory"
|
||||
|
||||
}, Logger);
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
private bool _disposed;
|
||||
protected void CheckDisposed()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(GetType().Name + " has been disposed and cannot be accessed.");
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_disposed = true;
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected async Task Vacuum(IDbConnection connection)
|
||||
{
|
||||
CheckDisposed();
|
||||
|
||||
await WriteLock.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
using (var cmd = connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "vacuum";
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorException("Failed to vacuum:", e);
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
WriteLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly object _disposeLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
||||
protected virtual void Dispose(bool dispose)
|
||||
{
|
||||
if (dispose)
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (_disposeLock)
|
||||
{
|
||||
WriteLock.Wait();
|
||||
|
||||
CloseConnection();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error disposing database", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void CloseConnection()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
181
Emby.Server.Core/Data/DataExtensions.cs
Normal file
181
Emby.Server.Core/Data/DataExtensions.cs
Normal file
@@ -0,0 +1,181 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace Emby.Server.Core.Data
|
||||
{
|
||||
public static class DataExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether the specified conn is open.
|
||||
/// </summary>
|
||||
/// <param name="conn">The conn.</param>
|
||||
/// <returns><c>true</c> if the specified conn is open; otherwise, <c>false</c>.</returns>
|
||||
public static bool IsOpen(this IDbConnection conn)
|
||||
{
|
||||
return conn.State == ConnectionState.Open;
|
||||
}
|
||||
|
||||
public static IDataParameter GetParameter(this IDbCommand cmd, int index)
|
||||
{
|
||||
return (IDataParameter)cmd.Parameters[index];
|
||||
}
|
||||
|
||||
public static IDataParameter Add(this IDataParameterCollection paramCollection, IDbCommand cmd, string name, DbType type)
|
||||
{
|
||||
var param = cmd.CreateParameter();
|
||||
|
||||
param.ParameterName = name;
|
||||
param.DbType = type;
|
||||
|
||||
paramCollection.Add(param);
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
public static IDataParameter Add(this IDataParameterCollection paramCollection, IDbCommand cmd, string name)
|
||||
{
|
||||
var param = cmd.CreateParameter();
|
||||
|
||||
param.ParameterName = name;
|
||||
|
||||
paramCollection.Add(param);
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a stream from a DataReader at a given ordinal
|
||||
/// </summary>
|
||||
/// <returns>Stream.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">reader</exception>
|
||||
public static Stream GetMemoryStream(this IDataReader reader, int ordinal, IMemoryStreamFactory streamProvider)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException("reader");
|
||||
}
|
||||
|
||||
var memoryStream = streamProvider.CreateNew();
|
||||
var num = 0L;
|
||||
var array = new byte[4096];
|
||||
long bytes;
|
||||
do
|
||||
{
|
||||
bytes = reader.GetBytes(ordinal, num, array, 0, array.Length);
|
||||
memoryStream.Write(array, 0, (int)bytes);
|
||||
num += bytes;
|
||||
}
|
||||
while (bytes > 0L);
|
||||
memoryStream.Position = 0;
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the queries.
|
||||
/// </summary>
|
||||
/// <param name="connection">The connection.</param>
|
||||
/// <param name="queries">The queries.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
/// <exception cref="System.ArgumentNullException">queries</exception>
|
||||
public static void RunQueries(this IDbConnection connection, string[] queries, ILogger logger)
|
||||
{
|
||||
if (queries == null)
|
||||
{
|
||||
throw new ArgumentNullException("queries");
|
||||
}
|
||||
|
||||
using (var tran = connection.BeginTransaction())
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var cmd = connection.CreateCommand())
|
||||
{
|
||||
foreach (var query in queries)
|
||||
{
|
||||
cmd.Transaction = tran;
|
||||
cmd.CommandText = query;
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
tran.Commit();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.ErrorException("Error running queries", e);
|
||||
tran.Rollback();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Attach(IDbConnection db, string path, string alias)
|
||||
{
|
||||
using (var cmd = db.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = string.Format("attach @dbPath as {0};", alias);
|
||||
cmd.Parameters.Add(cmd, "@dbPath", DbType.String);
|
||||
cmd.GetParameter(0).Value = path;
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes to bytes.
|
||||
/// </summary>
|
||||
/// <returns>System.Byte[][].</returns>
|
||||
/// <exception cref="System.ArgumentNullException">obj</exception>
|
||||
public static byte[] SerializeToBytes(this IJsonSerializer json, object obj, IMemoryStreamFactory streamProvider)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
throw new ArgumentNullException("obj");
|
||||
}
|
||||
|
||||
using (var stream = streamProvider.CreateNew())
|
||||
{
|
||||
json.SerializeToStream(obj, stream);
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddColumn(this IDbConnection connection, ILogger logger, string table, string columnName, string type)
|
||||
{
|
||||
using (var cmd = connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(" + table + ")";
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (!reader.IsDBNull(1))
|
||||
{
|
||||
var name = reader.GetString(1);
|
||||
|
||||
if (string.Equals(name, columnName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("alter table " + table);
|
||||
builder.AppendLine("add column " + columnName + " " + type);
|
||||
|
||||
connection.RunQueries(new[] { builder.ToString() }, logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
10
Emby.Server.Core/Data/IDbConnector.cs
Normal file
10
Emby.Server.Core/Data/IDbConnector.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Data;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Emby.Server.Core.Data
|
||||
{
|
||||
public interface IDbConnector
|
||||
{
|
||||
Task<IDbConnection> Connect(string dbPath, bool isReadOnly, bool enablePooling = false, int? cacheSize = null);
|
||||
}
|
||||
}
|
||||
408
Emby.Server.Core/Data/MediaStreamColumns.cs
Normal file
408
Emby.Server.Core/Data/MediaStreamColumns.cs
Normal file
@@ -0,0 +1,408 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Text;
|
||||
using MediaBrowser.Model.Logging;
|
||||
|
||||
namespace Emby.Server.Core.Data
|
||||
{
|
||||
public class MediaStreamColumns
|
||||
{
|
||||
private readonly IDbConnection _connection;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public MediaStreamColumns(IDbConnection connection, ILogger logger)
|
||||
{
|
||||
_connection = connection;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void AddColumns()
|
||||
{
|
||||
AddPixelFormatColumnCommand();
|
||||
AddBitDepthCommand();
|
||||
AddIsAnamorphicColumn();
|
||||
AddKeyFramesColumn();
|
||||
AddRefFramesCommand();
|
||||
AddCodecTagColumn();
|
||||
AddCommentColumn();
|
||||
AddNalColumn();
|
||||
AddIsAvcColumn();
|
||||
AddTitleColumn();
|
||||
AddTimeBaseColumn();
|
||||
AddCodecTimeBaseColumn();
|
||||
}
|
||||
|
||||
private void AddIsAvcColumn()
|
||||
{
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(mediastreams)";
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (!reader.IsDBNull(1))
|
||||
{
|
||||
var name = reader.GetString(1);
|
||||
|
||||
if (string.Equals(name, "IsAvc", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("alter table mediastreams");
|
||||
builder.AppendLine("add column IsAvc BIT NULL");
|
||||
|
||||
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
||||
}
|
||||
|
||||
private void AddTimeBaseColumn()
|
||||
{
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(mediastreams)";
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (!reader.IsDBNull(1))
|
||||
{
|
||||
var name = reader.GetString(1);
|
||||
|
||||
if (string.Equals(name, "TimeBase", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("alter table mediastreams");
|
||||
builder.AppendLine("add column TimeBase TEXT");
|
||||
|
||||
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
||||
}
|
||||
|
||||
private void AddCodecTimeBaseColumn()
|
||||
{
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(mediastreams)";
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (!reader.IsDBNull(1))
|
||||
{
|
||||
var name = reader.GetString(1);
|
||||
|
||||
if (string.Equals(name, "CodecTimeBase", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("alter table mediastreams");
|
||||
builder.AppendLine("add column CodecTimeBase TEXT");
|
||||
|
||||
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
||||
}
|
||||
|
||||
private void AddTitleColumn()
|
||||
{
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(mediastreams)";
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (!reader.IsDBNull(1))
|
||||
{
|
||||
var name = reader.GetString(1);
|
||||
|
||||
if (string.Equals(name, "Title", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("alter table mediastreams");
|
||||
builder.AppendLine("add column Title TEXT");
|
||||
|
||||
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
||||
}
|
||||
|
||||
private void AddNalColumn()
|
||||
{
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(mediastreams)";
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (!reader.IsDBNull(1))
|
||||
{
|
||||
var name = reader.GetString(1);
|
||||
|
||||
if (string.Equals(name, "NalLengthSize", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("alter table mediastreams");
|
||||
builder.AppendLine("add column NalLengthSize TEXT");
|
||||
|
||||
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
||||
}
|
||||
|
||||
private void AddCommentColumn()
|
||||
{
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(mediastreams)";
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (!reader.IsDBNull(1))
|
||||
{
|
||||
var name = reader.GetString(1);
|
||||
|
||||
if (string.Equals(name, "Comment", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("alter table mediastreams");
|
||||
builder.AppendLine("add column Comment TEXT");
|
||||
|
||||
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
||||
}
|
||||
|
||||
private void AddCodecTagColumn()
|
||||
{
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(mediastreams)";
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (!reader.IsDBNull(1))
|
||||
{
|
||||
var name = reader.GetString(1);
|
||||
|
||||
if (string.Equals(name, "CodecTag", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("alter table mediastreams");
|
||||
builder.AppendLine("add column CodecTag TEXT");
|
||||
|
||||
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
||||
}
|
||||
|
||||
private void AddPixelFormatColumnCommand()
|
||||
{
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(mediastreams)";
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (!reader.IsDBNull(1))
|
||||
{
|
||||
var name = reader.GetString(1);
|
||||
|
||||
if (string.Equals(name, "PixelFormat", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("alter table mediastreams");
|
||||
builder.AppendLine("add column PixelFormat TEXT");
|
||||
|
||||
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
||||
}
|
||||
|
||||
private void AddBitDepthCommand()
|
||||
{
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(mediastreams)";
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (!reader.IsDBNull(1))
|
||||
{
|
||||
var name = reader.GetString(1);
|
||||
|
||||
if (string.Equals(name, "BitDepth", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("alter table mediastreams");
|
||||
builder.AppendLine("add column BitDepth INT NULL");
|
||||
|
||||
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
||||
}
|
||||
|
||||
private void AddRefFramesCommand()
|
||||
{
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(mediastreams)";
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (!reader.IsDBNull(1))
|
||||
{
|
||||
var name = reader.GetString(1);
|
||||
|
||||
if (string.Equals(name, "RefFrames", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("alter table mediastreams");
|
||||
builder.AppendLine("add column RefFrames INT NULL");
|
||||
|
||||
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
||||
}
|
||||
|
||||
private void AddKeyFramesColumn()
|
||||
{
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(mediastreams)";
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (!reader.IsDBNull(1))
|
||||
{
|
||||
var name = reader.GetString(1);
|
||||
|
||||
if (string.Equals(name, "KeyFrames", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("alter table mediastreams");
|
||||
builder.AppendLine("add column KeyFrames TEXT NULL");
|
||||
|
||||
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
||||
}
|
||||
|
||||
private void AddIsAnamorphicColumn()
|
||||
{
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "PRAGMA table_info(mediastreams)";
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (!reader.IsDBNull(1))
|
||||
{
|
||||
var name = reader.GetString(1);
|
||||
|
||||
if (string.Equals(name, "IsAnamorphic", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine("alter table mediastreams");
|
||||
builder.AppendLine("add column IsAnamorphic BIT NULL");
|
||||
|
||||
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
312
Emby.Server.Core/Data/SqliteDisplayPreferencesRepository.cs
Normal file
312
Emby.Server.Core/Data/SqliteDisplayPreferencesRepository.cs
Normal file
@@ -0,0 +1,312 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace Emby.Server.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Class SQLiteDisplayPreferencesRepository
|
||||
/// </summary>
|
||||
public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository
|
||||
{
|
||||
private readonly IMemoryStreamFactory _memoryStreamProvider;
|
||||
|
||||
public SqliteDisplayPreferencesRepository(ILogManager logManager, IJsonSerializer jsonSerializer, IApplicationPaths appPaths, IDbConnector dbConnector, IMemoryStreamFactory memoryStreamProvider)
|
||||
: base(logManager, dbConnector)
|
||||
{
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_memoryStreamProvider = memoryStreamProvider;
|
||||
DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the repository
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return "SQLite";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _json serializer
|
||||
/// </summary>
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
|
||||
/// <summary>
|
||||
/// Opens the connection to the database
|
||||
/// </summary>
|
||||
/// <returns>Task.</returns>
|
||||
public async Task Initialize()
|
||||
{
|
||||
using (var connection = await CreateConnection().ConfigureAwait(false))
|
||||
{
|
||||
string[] queries = {
|
||||
|
||||
"create table if not exists userdisplaypreferences (id GUID, userId GUID, client text, data BLOB)",
|
||||
"create unique index if not exists userdisplaypreferencesindex on userdisplaypreferences (id, userId, client)"
|
||||
};
|
||||
|
||||
connection.RunQueries(queries, Logger);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the display preferences associated with an item in the repo
|
||||
/// </summary>
|
||||
/// <param name="displayPreferences">The display preferences.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="client">The client.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">item</exception>
|
||||
public async Task SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, CancellationToken cancellationToken)
|
||||
{
|
||||
if (displayPreferences == null)
|
||||
{
|
||||
throw new ArgumentNullException("displayPreferences");
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(displayPreferences.Id))
|
||||
{
|
||||
throw new ArgumentNullException("displayPreferences.Id");
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var serialized = _jsonSerializer.SerializeToBytes(displayPreferences, _memoryStreamProvider);
|
||||
|
||||
using (var connection = await CreateConnection().ConfigureAwait(false))
|
||||
{
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
try
|
||||
{
|
||||
transaction = connection.BeginTransaction();
|
||||
|
||||
using (var cmd = connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "replace into userdisplaypreferences (id, userid, client, data) values (@1, @2, @3, @4)";
|
||||
|
||||
cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = new Guid(displayPreferences.Id);
|
||||
cmd.Parameters.Add(cmd, "@2", DbType.Guid).Value = userId;
|
||||
cmd.Parameters.Add(cmd, "@3", DbType.String).Value = client;
|
||||
cmd.Parameters.Add(cmd, "@4", DbType.Binary).Value = serialized;
|
||||
|
||||
cmd.Transaction = transaction;
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorException("Failed to save display preferences:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save all display preferences associated with a user in the repo
|
||||
/// </summary>
|
||||
/// <param name="displayPreferences">The display preferences.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">item</exception>
|
||||
public async Task SaveAllDisplayPreferences(IEnumerable<DisplayPreferences> displayPreferences, Guid userId, CancellationToken cancellationToken)
|
||||
{
|
||||
if (displayPreferences == null)
|
||||
{
|
||||
throw new ArgumentNullException("displayPreferences");
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using (var connection = await CreateConnection().ConfigureAwait(false))
|
||||
{
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
try
|
||||
{
|
||||
transaction = connection.BeginTransaction();
|
||||
|
||||
foreach (var displayPreference in displayPreferences)
|
||||
{
|
||||
|
||||
var serialized = _jsonSerializer.SerializeToBytes(displayPreference, _memoryStreamProvider);
|
||||
|
||||
using (var cmd = connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "replace into userdisplaypreferences (id, userid, client, data) values (@1, @2, @3, @4)";
|
||||
|
||||
cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = new Guid(displayPreference.Id);
|
||||
cmd.Parameters.Add(cmd, "@2", DbType.Guid).Value = userId;
|
||||
cmd.Parameters.Add(cmd, "@3", DbType.String).Value = displayPreference.Client;
|
||||
cmd.Parameters.Add(cmd, "@4", DbType.Binary).Value = serialized;
|
||||
|
||||
cmd.Transaction = transaction;
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorException("Failed to save display preferences:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display preferences.
|
||||
/// </summary>
|
||||
/// <param name="displayPreferencesId">The display preferences id.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="client">The client.</param>
|
||||
/// <returns>Task{DisplayPreferences}.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">item</exception>
|
||||
public DisplayPreferences GetDisplayPreferences(string displayPreferencesId, Guid userId, string client)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(displayPreferencesId))
|
||||
{
|
||||
throw new ArgumentNullException("displayPreferencesId");
|
||||
}
|
||||
|
||||
var guidId = displayPreferencesId.GetMD5();
|
||||
|
||||
using (var connection = CreateConnection(true).Result)
|
||||
{
|
||||
using (var cmd = connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "select data from userdisplaypreferences where id = @id and userId=@userId and client=@client";
|
||||
|
||||
cmd.Parameters.Add(cmd, "@id", DbType.Guid).Value = guidId;
|
||||
cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
|
||||
cmd.Parameters.Add(cmd, "@client", DbType.String).Value = client;
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
|
||||
{
|
||||
if (reader.Read())
|
||||
{
|
||||
using (var stream = reader.GetMemoryStream(0, _memoryStreamProvider))
|
||||
{
|
||||
return _jsonSerializer.DeserializeFromStream<DisplayPreferences>(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new DisplayPreferences
|
||||
{
|
||||
Id = guidId.ToString("N")
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all display preferences for the given user.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <returns>Task{DisplayPreferences}.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">item</exception>
|
||||
public IEnumerable<DisplayPreferences> GetAllDisplayPreferences(Guid userId)
|
||||
{
|
||||
var list = new List<DisplayPreferences>();
|
||||
|
||||
using (var connection = CreateConnection(true).Result)
|
||||
{
|
||||
using (var cmd = connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "select data from userdisplaypreferences where userId=@userId";
|
||||
|
||||
cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
using (var stream = reader.GetMemoryStream(0, _memoryStreamProvider))
|
||||
{
|
||||
list.Add(_jsonSerializer.DeserializeFromStream<DisplayPreferences>(stream));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public Task SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken)
|
||||
{
|
||||
return SaveDisplayPreferences(displayPreferences, new Guid(userId), client, cancellationToken);
|
||||
}
|
||||
|
||||
public DisplayPreferences GetDisplayPreferences(string displayPreferencesId, string userId, string client)
|
||||
{
|
||||
return GetDisplayPreferences(displayPreferencesId, new Guid(userId), client);
|
||||
}
|
||||
}
|
||||
}
|
||||
408
Emby.Server.Core/Data/SqliteFileOrganizationRepository.cs
Normal file
408
Emby.Server.Core/Data/SqliteFileOrganizationRepository.cs
Normal file
@@ -0,0 +1,408 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.FileOrganization;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
namespace Emby.Server.Core.Data
|
||||
{
|
||||
public class SqliteFileOrganizationRepository : BaseSqliteRepository, IFileOrganizationRepository, IDisposable
|
||||
{
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
|
||||
public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector connector) : base(logManager, connector)
|
||||
{
|
||||
DbFilePath = Path.Combine(appPaths.DataPath, "fileorganization.db");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the connection to the database
|
||||
/// </summary>
|
||||
/// <returns>Task.</returns>
|
||||
public async Task Initialize()
|
||||
{
|
||||
using (var connection = await CreateConnection().ConfigureAwait(false))
|
||||
{
|
||||
string[] queries = {
|
||||
|
||||
"create table if not exists FileOrganizerResults (ResultId GUID PRIMARY KEY, OriginalPath TEXT, TargetPath TEXT, FileLength INT, OrganizationDate datetime, Status TEXT, OrganizationType TEXT, StatusMessage TEXT, ExtractedName TEXT, ExtractedYear int null, ExtractedSeasonNumber int null, ExtractedEpisodeNumber int null, ExtractedEndingEpisodeNumber, DuplicatePaths TEXT int null)",
|
||||
"create index if not exists idx_FileOrganizerResults on FileOrganizerResults(ResultId)"
|
||||
};
|
||||
|
||||
connection.RunQueries(queries, Logger);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken)
|
||||
{
|
||||
if (result == null)
|
||||
{
|
||||
throw new ArgumentNullException("result");
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using (var connection = await CreateConnection().ConfigureAwait(false))
|
||||
{
|
||||
using (var saveResultCommand = connection.CreateCommand())
|
||||
{
|
||||
saveResultCommand.CommandText = "replace into FileOrganizerResults (ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths) values (@ResultId, @OriginalPath, @TargetPath, @FileLength, @OrganizationDate, @Status, @OrganizationType, @StatusMessage, @ExtractedName, @ExtractedYear, @ExtractedSeasonNumber, @ExtractedEpisodeNumber, @ExtractedEndingEpisodeNumber, @DuplicatePaths)";
|
||||
|
||||
saveResultCommand.Parameters.Add(saveResultCommand, "@ResultId");
|
||||
saveResultCommand.Parameters.Add(saveResultCommand, "@OriginalPath");
|
||||
saveResultCommand.Parameters.Add(saveResultCommand, "@TargetPath");
|
||||
saveResultCommand.Parameters.Add(saveResultCommand, "@FileLength");
|
||||
saveResultCommand.Parameters.Add(saveResultCommand, "@OrganizationDate");
|
||||
saveResultCommand.Parameters.Add(saveResultCommand, "@Status");
|
||||
saveResultCommand.Parameters.Add(saveResultCommand, "@OrganizationType");
|
||||
saveResultCommand.Parameters.Add(saveResultCommand, "@StatusMessage");
|
||||
saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedName");
|
||||
saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedYear");
|
||||
saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedSeasonNumber");
|
||||
saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedEpisodeNumber");
|
||||
saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedEndingEpisodeNumber");
|
||||
saveResultCommand.Parameters.Add(saveResultCommand, "@DuplicatePaths");
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
try
|
||||
{
|
||||
transaction = connection.BeginTransaction();
|
||||
|
||||
var index = 0;
|
||||
|
||||
saveResultCommand.GetParameter(index++).Value = new Guid(result.Id);
|
||||
saveResultCommand.GetParameter(index++).Value = result.OriginalPath;
|
||||
saveResultCommand.GetParameter(index++).Value = result.TargetPath;
|
||||
saveResultCommand.GetParameter(index++).Value = result.FileSize;
|
||||
saveResultCommand.GetParameter(index++).Value = result.Date;
|
||||
saveResultCommand.GetParameter(index++).Value = result.Status.ToString();
|
||||
saveResultCommand.GetParameter(index++).Value = result.Type.ToString();
|
||||
saveResultCommand.GetParameter(index++).Value = result.StatusMessage;
|
||||
saveResultCommand.GetParameter(index++).Value = result.ExtractedName;
|
||||
saveResultCommand.GetParameter(index++).Value = result.ExtractedYear;
|
||||
saveResultCommand.GetParameter(index++).Value = result.ExtractedSeasonNumber;
|
||||
saveResultCommand.GetParameter(index++).Value = result.ExtractedEpisodeNumber;
|
||||
saveResultCommand.GetParameter(index++).Value = result.ExtractedEndingEpisodeNumber;
|
||||
saveResultCommand.GetParameter(index).Value = string.Join("|", result.DuplicatePaths.ToArray());
|
||||
|
||||
saveResultCommand.Transaction = transaction;
|
||||
|
||||
saveResultCommand.ExecuteNonQuery();
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorException("Failed to save FileOrganizationResult:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Delete(string id)
|
||||
{
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
throw new ArgumentNullException("id");
|
||||
}
|
||||
|
||||
using (var connection = await CreateConnection().ConfigureAwait(false))
|
||||
{
|
||||
using (var deleteResultCommand = connection.CreateCommand())
|
||||
{
|
||||
deleteResultCommand.CommandText = "delete from FileOrganizerResults where ResultId = @ResultId";
|
||||
|
||||
deleteResultCommand.Parameters.Add(deleteResultCommand, "@ResultId");
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
try
|
||||
{
|
||||
transaction = connection.BeginTransaction();
|
||||
|
||||
deleteResultCommand.GetParameter(0).Value = new Guid(id);
|
||||
|
||||
deleteResultCommand.Transaction = transaction;
|
||||
|
||||
deleteResultCommand.ExecuteNonQuery();
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorException("Failed to delete FileOrganizationResult:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteAll()
|
||||
{
|
||||
using (var connection = await CreateConnection().ConfigureAwait(false))
|
||||
{
|
||||
using (var cmd = connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "delete from FileOrganizerResults";
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
try
|
||||
{
|
||||
transaction = connection.BeginTransaction();
|
||||
|
||||
cmd.Transaction = transaction;
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorException("Failed to delete results", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public QueryResult<FileOrganizationResult> GetResults(FileOrganizationResultQuery query)
|
||||
{
|
||||
if (query == null)
|
||||
{
|
||||
throw new ArgumentNullException("query");
|
||||
}
|
||||
|
||||
using (var connection = CreateConnection(true).Result)
|
||||
{
|
||||
using (var cmd = connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "SELECT ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults";
|
||||
|
||||
if (query.StartIndex.HasValue && query.StartIndex.Value > 0)
|
||||
{
|
||||
cmd.CommandText += string.Format(" WHERE ResultId NOT IN (SELECT ResultId FROM FileOrganizerResults ORDER BY OrganizationDate desc LIMIT {0})",
|
||||
query.StartIndex.Value.ToString(_usCulture));
|
||||
}
|
||||
|
||||
cmd.CommandText += " ORDER BY OrganizationDate desc";
|
||||
|
||||
if (query.Limit.HasValue)
|
||||
{
|
||||
cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture);
|
||||
}
|
||||
|
||||
cmd.CommandText += "; select count (ResultId) from FileOrganizerResults";
|
||||
|
||||
var list = new List<FileOrganizationResult>();
|
||||
var count = 0;
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
list.Add(GetResult(reader));
|
||||
}
|
||||
|
||||
if (reader.NextResult() && reader.Read())
|
||||
{
|
||||
count = reader.GetInt32(0);
|
||||
}
|
||||
}
|
||||
|
||||
return new QueryResult<FileOrganizationResult>()
|
||||
{
|
||||
Items = list.ToArray(),
|
||||
TotalRecordCount = count
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FileOrganizationResult GetResult(string id)
|
||||
{
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
throw new ArgumentNullException("id");
|
||||
}
|
||||
|
||||
using (var connection = CreateConnection(true).Result)
|
||||
{
|
||||
var guid = new Guid(id);
|
||||
|
||||
using (var cmd = connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "select ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults where ResultId=@Id";
|
||||
|
||||
cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid;
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
|
||||
{
|
||||
if (reader.Read())
|
||||
{
|
||||
return GetResult(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public FileOrganizationResult GetResult(IDataReader reader)
|
||||
{
|
||||
var index = 0;
|
||||
|
||||
var result = new FileOrganizationResult
|
||||
{
|
||||
Id = reader.GetGuid(0).ToString("N")
|
||||
};
|
||||
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
result.OriginalPath = reader.GetString(index);
|
||||
}
|
||||
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
result.TargetPath = reader.GetString(index);
|
||||
}
|
||||
|
||||
index++;
|
||||
result.FileSize = reader.GetInt64(index);
|
||||
|
||||
index++;
|
||||
result.Date = reader.GetDateTime(index).ToUniversalTime();
|
||||
|
||||
index++;
|
||||
result.Status = (FileSortingStatus)Enum.Parse(typeof(FileSortingStatus), reader.GetString(index), true);
|
||||
|
||||
index++;
|
||||
result.Type = (FileOrganizerType)Enum.Parse(typeof(FileOrganizerType), reader.GetString(index), true);
|
||||
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
result.StatusMessage = reader.GetString(index);
|
||||
}
|
||||
|
||||
result.OriginalFileName = Path.GetFileName(result.OriginalPath);
|
||||
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
result.ExtractedName = reader.GetString(index);
|
||||
}
|
||||
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
result.ExtractedYear = reader.GetInt32(index);
|
||||
}
|
||||
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
result.ExtractedSeasonNumber = reader.GetInt32(index);
|
||||
}
|
||||
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
result.ExtractedEpisodeNumber = reader.GetInt32(index);
|
||||
}
|
||||
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
result.ExtractedEndingEpisodeNumber = reader.GetInt32(index);
|
||||
}
|
||||
|
||||
index++;
|
||||
if (!reader.IsDBNull(index))
|
||||
{
|
||||
result.DuplicatePaths = reader.GetString(index).Split('|').Where(i => !string.IsNullOrEmpty(i)).ToList();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
5423
Emby.Server.Core/Data/SqliteItemRepository.cs
Normal file
5423
Emby.Server.Core/Data/SqliteItemRepository.cs
Normal file
File diff suppressed because it is too large
Load Diff
453
Emby.Server.Core/Data/SqliteUserDataRepository.cs
Normal file
453
Emby.Server.Core/Data/SqliteUserDataRepository.cs
Normal file
@@ -0,0 +1,453 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Logging;
|
||||
|
||||
namespace Emby.Server.Core.Data
|
||||
{
|
||||
public class SqliteUserDataRepository : BaseSqliteRepository, IUserDataRepository
|
||||
{
|
||||
private IDbConnection _connection;
|
||||
|
||||
public SqliteUserDataRepository(ILogManager logManager, IApplicationPaths appPaths, IDbConnector connector) : base(logManager, connector)
|
||||
{
|
||||
DbFilePath = Path.Combine(appPaths.DataPath, "userdata_v2.db");
|
||||
}
|
||||
|
||||
protected override bool EnableConnectionPooling
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the repository
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return "SQLite";
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task<IDbConnection> CreateConnection(bool isReadOnly = false)
|
||||
{
|
||||
var connection = await DbConnector.Connect(DbFilePath, false, false, 10000).ConfigureAwait(false);
|
||||
|
||||
connection.RunQueries(new[]
|
||||
{
|
||||
"pragma temp_store = memory"
|
||||
|
||||
}, Logger);
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the connection to the database
|
||||
/// </summary>
|
||||
/// <returns>Task.</returns>
|
||||
public async Task Initialize(IDbConnection connection, SemaphoreSlim writeLock)
|
||||
{
|
||||
WriteLock.Dispose();
|
||||
WriteLock = writeLock;
|
||||
_connection = connection;
|
||||
|
||||
string[] queries = {
|
||||
|
||||
"create table if not exists UserDataDb.userdata (key nvarchar, userId GUID, rating float null, played bit, playCount int, isFavorite bit, playbackPositionTicks bigint, lastPlayedDate datetime null)",
|
||||
|
||||
"drop index if exists UserDataDb.idx_userdata",
|
||||
"drop index if exists UserDataDb.idx_userdata1",
|
||||
"drop index if exists UserDataDb.idx_userdata2",
|
||||
"drop index if exists UserDataDb.userdataindex1",
|
||||
|
||||
"create unique index if not exists UserDataDb.userdataindex on userdata (key, userId)",
|
||||
"create index if not exists UserDataDb.userdataindex2 on userdata (key, userId, played)",
|
||||
"create index if not exists UserDataDb.userdataindex3 on userdata (key, userId, playbackPositionTicks)",
|
||||
"create index if not exists UserDataDb.userdataindex4 on userdata (key, userId, isFavorite)",
|
||||
|
||||
//pragmas
|
||||
"pragma temp_store = memory",
|
||||
|
||||
"pragma shrink_memory"
|
||||
};
|
||||
|
||||
_connection.RunQueries(queries, Logger);
|
||||
|
||||
_connection.AddColumn(Logger, "userdata", "AudioStreamIndex", "int");
|
||||
_connection.AddColumn(Logger, "userdata", "SubtitleStreamIndex", "int");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the user data.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <param name="userData">The user data.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">userData
|
||||
/// or
|
||||
/// cancellationToken
|
||||
/// or
|
||||
/// userId
|
||||
/// or
|
||||
/// userDataId</exception>
|
||||
public Task SaveUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken)
|
||||
{
|
||||
if (userData == null)
|
||||
{
|
||||
throw new ArgumentNullException("userData");
|
||||
}
|
||||
if (userId == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentNullException("userId");
|
||||
}
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
return PersistUserData(userId, key, userData, cancellationToken);
|
||||
}
|
||||
|
||||
public Task SaveAllUserData(Guid userId, IEnumerable<UserItemData> userData, CancellationToken cancellationToken)
|
||||
{
|
||||
if (userData == null)
|
||||
{
|
||||
throw new ArgumentNullException("userData");
|
||||
}
|
||||
if (userId == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentNullException("userId");
|
||||
}
|
||||
|
||||
return PersistAllUserData(userId, userData, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Persists the user data.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <param name="userData">The user data.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public async Task PersistUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
try
|
||||
{
|
||||
transaction = _connection.BeginTransaction();
|
||||
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)";
|
||||
|
||||
cmd.Parameters.Add(cmd, "@key", DbType.String).Value = key;
|
||||
cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
|
||||
cmd.Parameters.Add(cmd, "@rating", DbType.Double).Value = userData.Rating;
|
||||
cmd.Parameters.Add(cmd, "@played", DbType.Boolean).Value = userData.Played;
|
||||
cmd.Parameters.Add(cmd, "@playCount", DbType.Int32).Value = userData.PlayCount;
|
||||
cmd.Parameters.Add(cmd, "@isFavorite", DbType.Boolean).Value = userData.IsFavorite;
|
||||
cmd.Parameters.Add(cmd, "@playbackPositionTicks", DbType.Int64).Value = userData.PlaybackPositionTicks;
|
||||
cmd.Parameters.Add(cmd, "@lastPlayedDate", DbType.DateTime).Value = userData.LastPlayedDate;
|
||||
cmd.Parameters.Add(cmd, "@AudioStreamIndex", DbType.Int32).Value = userData.AudioStreamIndex;
|
||||
cmd.Parameters.Add(cmd, "@SubtitleStreamIndex", DbType.Int32).Value = userData.SubtitleStreamIndex;
|
||||
|
||||
cmd.Transaction = transaction;
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorException("Failed to save user data:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Dispose();
|
||||
}
|
||||
|
||||
WriteLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Persist all user data for the specified user
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="userData"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
private async Task PersistAllUserData(Guid userId, IEnumerable<UserItemData> userData, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
try
|
||||
{
|
||||
transaction = _connection.BeginTransaction();
|
||||
|
||||
foreach (var userItemData in userData)
|
||||
{
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)";
|
||||
|
||||
cmd.Parameters.Add(cmd, "@key", DbType.String).Value = userItemData.Key;
|
||||
cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
|
||||
cmd.Parameters.Add(cmd, "@rating", DbType.Double).Value = userItemData.Rating;
|
||||
cmd.Parameters.Add(cmd, "@played", DbType.Boolean).Value = userItemData.Played;
|
||||
cmd.Parameters.Add(cmd, "@playCount", DbType.Int32).Value = userItemData.PlayCount;
|
||||
cmd.Parameters.Add(cmd, "@isFavorite", DbType.Boolean).Value = userItemData.IsFavorite;
|
||||
cmd.Parameters.Add(cmd, "@playbackPositionTicks", DbType.Int64).Value = userItemData.PlaybackPositionTicks;
|
||||
cmd.Parameters.Add(cmd, "@lastPlayedDate", DbType.DateTime).Value = userItemData.LastPlayedDate;
|
||||
cmd.Parameters.Add(cmd, "@AudioStreamIndex", DbType.Int32).Value = userItemData.AudioStreamIndex;
|
||||
cmd.Parameters.Add(cmd, "@SubtitleStreamIndex", DbType.Int32).Value = userItemData.SubtitleStreamIndex;
|
||||
|
||||
cmd.Transaction = transaction;
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorException("Failed to save user data:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Dispose();
|
||||
}
|
||||
|
||||
WriteLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <returns>Task{UserItemData}.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">
|
||||
/// userId
|
||||
/// or
|
||||
/// key
|
||||
/// </exception>
|
||||
public UserItemData GetUserData(Guid userId, string key)
|
||||
{
|
||||
if (userId == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentNullException("userId");
|
||||
}
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key = @key and userId=@userId";
|
||||
|
||||
cmd.Parameters.Add(cmd, "@key", DbType.String).Value = key;
|
||||
cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
|
||||
{
|
||||
if (reader.Read())
|
||||
{
|
||||
return ReadRow(reader);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public UserItemData GetUserData(Guid userId, List<string> keys)
|
||||
{
|
||||
if (userId == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentNullException("userId");
|
||||
}
|
||||
if (keys == null)
|
||||
{
|
||||
throw new ArgumentNullException("keys");
|
||||
}
|
||||
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
var index = 0;
|
||||
var userdataKeys = new List<string>();
|
||||
var builder = new StringBuilder();
|
||||
foreach (var key in keys)
|
||||
{
|
||||
var paramName = "@Key" + index;
|
||||
userdataKeys.Add("Key =" + paramName);
|
||||
cmd.Parameters.Add(cmd, paramName, DbType.String).Value = key;
|
||||
builder.Append(" WHEN Key=" + paramName + " THEN " + index);
|
||||
index++;
|
||||
break;
|
||||
}
|
||||
|
||||
var keyText = string.Join(" OR ", userdataKeys.ToArray());
|
||||
|
||||
cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId AND (" + keyText + ") ";
|
||||
|
||||
cmd.CommandText += " ORDER BY (Case " + builder + " Else " + keys.Count.ToString(CultureInfo.InvariantCulture) + " End )";
|
||||
cmd.CommandText += " LIMIT 1";
|
||||
|
||||
cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
|
||||
{
|
||||
if (reader.Read())
|
||||
{
|
||||
return ReadRow(reader);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return all user-data associated with the given user
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<UserItemData> GetAllUserData(Guid userId)
|
||||
{
|
||||
if (userId == Guid.Empty)
|
||||
{
|
||||
throw new ArgumentNullException("userId");
|
||||
}
|
||||
|
||||
using (var cmd = _connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId";
|
||||
|
||||
cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId;
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
yield return ReadRow(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a row from the specified reader into the provided userData object
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
private UserItemData ReadRow(IDataReader reader)
|
||||
{
|
||||
var userData = new UserItemData();
|
||||
|
||||
userData.Key = reader.GetString(0);
|
||||
userData.UserId = reader.GetGuid(1);
|
||||
|
||||
if (!reader.IsDBNull(2))
|
||||
{
|
||||
userData.Rating = reader.GetDouble(2);
|
||||
}
|
||||
|
||||
userData.Played = reader.GetBoolean(3);
|
||||
userData.PlayCount = reader.GetInt32(4);
|
||||
userData.IsFavorite = reader.GetBoolean(5);
|
||||
userData.PlaybackPositionTicks = reader.GetInt64(6);
|
||||
|
||||
if (!reader.IsDBNull(7))
|
||||
{
|
||||
userData.LastPlayedDate = reader.GetDateTime(7).ToUniversalTime();
|
||||
}
|
||||
|
||||
if (!reader.IsDBNull(8))
|
||||
{
|
||||
userData.AudioStreamIndex = reader.GetInt32(8);
|
||||
}
|
||||
|
||||
if (!reader.IsDBNull(9))
|
||||
{
|
||||
userData.SubtitleStreamIndex = reader.GetInt32(9);
|
||||
}
|
||||
|
||||
return userData;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool dispose)
|
||||
{
|
||||
// handled by library database
|
||||
}
|
||||
|
||||
protected override void CloseConnection()
|
||||
{
|
||||
// handled by library database
|
||||
}
|
||||
}
|
||||
}
|
||||
237
Emby.Server.Core/Data/SqliteUserRepository.cs
Normal file
237
Emby.Server.Core/Data/SqliteUserRepository.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace Emby.Server.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Class SQLiteUserRepository
|
||||
/// </summary>
|
||||
public class SqliteUserRepository : BaseSqliteRepository, IUserRepository
|
||||
{
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly IMemoryStreamFactory _memoryStreamProvider;
|
||||
|
||||
public SqliteUserRepository(ILogManager logManager, IServerApplicationPaths appPaths, IJsonSerializer jsonSerializer, IDbConnector dbConnector, IMemoryStreamFactory memoryStreamProvider) : base(logManager, dbConnector)
|
||||
{
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_memoryStreamProvider = memoryStreamProvider;
|
||||
|
||||
DbFilePath = Path.Combine(appPaths.DataPath, "users.db");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the repository
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return "SQLite";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the connection to the database
|
||||
/// </summary>
|
||||
/// <returns>Task.</returns>
|
||||
public async Task Initialize()
|
||||
{
|
||||
using (var connection = await CreateConnection().ConfigureAwait(false))
|
||||
{
|
||||
string[] queries = {
|
||||
|
||||
"create table if not exists users (guid GUID primary key, data BLOB)",
|
||||
"create index if not exists idx_users on users(guid)",
|
||||
"create table if not exists schema_version (table_name primary key, version)",
|
||||
|
||||
"pragma shrink_memory"
|
||||
};
|
||||
|
||||
connection.RunQueries(queries, Logger);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save a user in the repo
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">user</exception>
|
||||
public async Task SaveUser(User user, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var serialized = _jsonSerializer.SerializeToBytes(user, _memoryStreamProvider);
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using (var connection = await CreateConnection().ConfigureAwait(false))
|
||||
{
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
try
|
||||
{
|
||||
transaction = connection.BeginTransaction();
|
||||
|
||||
using (var cmd = connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "replace into users (guid, data) values (@1, @2)";
|
||||
cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = user.Id;
|
||||
cmd.Parameters.Add(cmd, "@2", DbType.Binary).Value = serialized;
|
||||
|
||||
cmd.Transaction = transaction;
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorException("Failed to save user:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve all users from the database
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{User}.</returns>
|
||||
public IEnumerable<User> RetrieveAllUsers()
|
||||
{
|
||||
var list = new List<User>();
|
||||
|
||||
using (var connection = CreateConnection(true).Result)
|
||||
{
|
||||
using (var cmd = connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "select guid,data from users";
|
||||
|
||||
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
var id = reader.GetGuid(0);
|
||||
|
||||
using (var stream = reader.GetMemoryStream(1, _memoryStreamProvider))
|
||||
{
|
||||
var user = _jsonSerializer.DeserializeFromStream<User>(stream);
|
||||
user.Id = id;
|
||||
list.Add(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the user.
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">user</exception>
|
||||
public async Task DeleteUser(User user, CancellationToken cancellationToken)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException("user");
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using (var connection = await CreateConnection().ConfigureAwait(false))
|
||||
{
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
try
|
||||
{
|
||||
transaction = connection.BeginTransaction();
|
||||
|
||||
using (var cmd = connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = "delete from users where guid=@guid";
|
||||
|
||||
cmd.Parameters.Add(cmd, "@guid", DbType.Guid).Value = user.Id;
|
||||
|
||||
cmd.Transaction = transaction;
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorException("Failed to delete user:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (transaction != null)
|
||||
{
|
||||
transaction.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
47
Emby.Server.Core/Data/TypeMapper.cs
Normal file
47
Emby.Server.Core/Data/TypeMapper.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
|
||||
namespace Emby.Server.Core.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Class TypeMapper
|
||||
/// </summary>
|
||||
public class TypeMapper
|
||||
{
|
||||
/// <summary>
|
||||
/// This holds all the types in the running assemblies so that we can de-serialize properly when we don't have strong types
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<string, Type> _typeMap = new ConcurrentDictionary<string, Type>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type.
|
||||
/// </summary>
|
||||
/// <param name="typeName">Name of the type.</param>
|
||||
/// <returns>Type.</returns>
|
||||
/// <exception cref="System.ArgumentNullException"></exception>
|
||||
public Type GetType(string typeName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(typeName))
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
|
||||
return _typeMap.GetOrAdd(typeName, LookupType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lookups the type.
|
||||
/// </summary>
|
||||
/// <param name="typeName">Name of the type.</param>
|
||||
/// <returns>Type.</returns>
|
||||
private Type LookupType(string typeName)
|
||||
{
|
||||
return AppDomain
|
||||
.CurrentDomain
|
||||
.GetAssemblies()
|
||||
.Select(a => a.GetType(typeName, false))
|
||||
.FirstOrDefault(t => t != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user