@ -4,7 +4,9 @@ using MediaBrowser.Model.FileOrganization;
using MediaBrowser.Model.Logging ;
using MediaBrowser.Model.Querying ;
using System ;
using System.Collections.Generic ;
using System.Data ;
using System.Globalization ;
using System.IO ;
using System.Threading ;
using System.Threading.Tasks ;
@ -21,6 +23,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
private SqliteShrinkMemoryTimer _shrinkMemoryTimer ;
private readonly IServerApplicationPaths _appPaths ;
private readonly CultureInfo _usCulture = new CultureInfo ( "en-US" ) ;
private IDbCommand _saveResultCommand ;
private IDbCommand _deleteResultCommand ;
public SqliteFileOrganizationRepository ( ILogManager logManager , IServerApplicationPaths appPaths )
{
_appPaths = appPaths ;
@ -40,6 +47,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
string [ ] queries = {
"create table if not exists organizationresults (ResultId GUID PRIMARY KEY, OriginalPath TEXT, TargetPath TEXT, OrganizationDate datetime, Status TEXT, OrganizationType TEXT, StatusMessage TEXT, ExtractedName TEXT, ExtractedYear int null)" ,
"create index if not exists idx_organizationresults on organizationresults(ResultId)" ,
//pragmas
"pragma temp_store = memory" ,
@ -55,16 +65,259 @@ namespace MediaBrowser.Server.Implementations.Persistence
private void PrepareStatements ( )
{
_saveResultCommand = _connection . CreateCommand ( ) ;
_saveResultCommand . CommandText = "replace into organizationresults (ResultId, OriginalPath, TargetPath, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear) values (@ResultId, @OriginalPath, @TargetPath, @OrganizationDate, @Status, @OrganizationType, @StatusMessage, @ExtractedName, @ExtractedYear)" ;
_saveResultCommand . Parameters . Add ( _saveResultCommand , "@ResultId" ) ;
_saveResultCommand . Parameters . Add ( _saveResultCommand , "@OriginalPath" ) ;
_saveResultCommand . Parameters . Add ( _saveResultCommand , "@TargetPath" ) ;
_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" ) ;
_deleteResultCommand = _connection . CreateCommand ( ) ;
_deleteResultCommand . CommandText = "delete from organizationresults where ResultId = @ResultId" ;
_deleteResultCommand . Parameters . Add ( _saveResultCommand , "@ResultId" ) ;
}
public Task SaveResult ( FileOrganizationResult result , CancellationToken cancellationToken )
public async Task SaveResult ( FileOrganizationResult result , CancellationToken cancellationToken )
{
return Task . FromResult ( true ) ;
if ( result = = null )
{
throw new ArgumentNullException ( "result" ) ;
}
cancellationToken . ThrowIfCancellationRequested ( ) ;
await _writeLock . WaitAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
IDbTransaction transaction = null ;
try
{
transaction = _connection . BeginTransaction ( ) ;
_saveResultCommand . GetParameter ( 0 ) . Value = new Guid ( result . Id ) ;
_saveResultCommand . GetParameter ( 1 ) . Value = result . OriginalPath ;
_saveResultCommand . GetParameter ( 2 ) . Value = result . TargetPath ;
_saveResultCommand . GetParameter ( 3 ) . Value = result . Date ;
_saveResultCommand . GetParameter ( 4 ) . Value = result . Status . ToString ( ) ;
_saveResultCommand . GetParameter ( 5 ) . Value = result . Type . ToString ( ) ;
_saveResultCommand . GetParameter ( 6 ) . Value = result . StatusMessage ;
_saveResultCommand . GetParameter ( 7 ) . Value = result . ExtractedName ;
_saveResultCommand . GetParameter ( 8 ) . Value = result . ExtractedYear ;
_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 ( ) ;
}
_writeLock . Release ( ) ;
}
}
public async Task Delete ( string id )
{
if ( string . IsNullOrEmpty ( id ) )
{
throw new ArgumentNullException ( "id" ) ;
}
await _writeLock . WaitAsync ( ) . ConfigureAwait ( false ) ;
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 save FileOrganizationResult:" , e ) ;
if ( transaction ! = null )
{
transaction . Rollback ( ) ;
}
throw ;
}
finally
{
if ( transaction ! = null )
{
transaction . Dispose ( ) ;
}
_writeLock . Release ( ) ;
}
}
public QueryResult < FileOrganizationResult > GetResults ( FileOrganizationResultQuery query )
{
return new QueryResult < FileOrganizationResult > ( ) ;
if ( query = = null )
{
throw new ArgumentNullException ( "query" ) ;
}
using ( var cmd = _connection . CreateCommand ( ) )
{
cmd . CommandText = "SELECT ResultId, OriginalPath, TargetPath, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear from organizationresults" ;
if ( query . StartIndex . HasValue & & query . StartIndex . Value > 0 )
{
cmd . CommandText + = string . Format ( " WHERE ResultId NOT IN (SELECT ResultId FROM organizationresults 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 organizationresults" ;
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" ) ;
}
var guid = new Guid ( id ) ;
using ( var cmd = _connection . CreateCommand ( ) )
{
cmd . CommandText = "select ResultId, OriginalPath, TargetPath, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear from organizationresults 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 result = new FileOrganizationResult
{
Id = reader . GetGuid ( 0 ) . ToString ( "N" )
} ;
if ( ! reader . IsDBNull ( 1 ) )
{
result . OriginalPath = reader . GetString ( 1 ) ;
}
if ( ! reader . IsDBNull ( 2 ) )
{
result . TargetPath = reader . GetString ( 2 ) ;
}
result . Date = reader . GetDateTime ( 3 ) . ToUniversalTime ( ) ;
result . Status = ( FileSortingStatus ) Enum . Parse ( typeof ( FileSortingStatus ) , reader . GetString ( 4 ) , true ) ;
result . Type = ( FileOrganizerType ) Enum . Parse ( typeof ( FileOrganizerType ) , reader . GetString ( 5 ) , true ) ;
if ( ! reader . IsDBNull ( 6 ) )
{
result . StatusMessage = reader . GetString ( 6 ) ;
}
result . OriginalFileName = Path . GetFileName ( result . OriginalPath ) ;
if ( ! reader . IsDBNull ( 7 ) )
{
result . ExtractedName = reader . GetString ( 7 ) ;
}
if ( ! reader . IsDBNull ( 8 ) )
{
result . ExtractedYear = reader . GetInt32 ( 8 ) ;
}
return result ;
}
/// <summary>