Version 210

This commit is contained in:
Hydrus Network Developer 2016-06-15 13:59:44 -05:00
parent b063f24298
commit eccf03aaa4
20 changed files with 571 additions and 531 deletions

View File

@ -27,7 +27,9 @@ try:
from include import HydrusLogger
import traceback
with HydrusLogger.HydrusLogger( 'client.log' ) as logger:
log_path = os.path.join( HC.DB_DIR, 'client.log' )
with HydrusLogger.HydrusLogger( log_path ) as logger:
try:

View File

@ -8,6 +8,26 @@
<div class="content">
<h3>changelog</h3>
<ul>
<li><h3>version 210</h3></li>
<ul>
<li>manage tags dialog now launches much faster when thousands of thumbs are selected</li>
<li>manage tags dialog now has a prototype 'do this for all' checkbox to make mass selected-tag editing a bit quicker</li>
<li>polished the new disk cache turbo mode, added free memory limits and more options</li>
<li>a bit of disk cache population now runs on client boot, just to kick things off</li>
<li>a full disk cache population now runs before repo sync</li>
<li>the client now keeps about 200MB of itself in the disk cache during idle maintenance</li>
<li>the update files in client_updates are now stored compressed</li>
<li>the log files and 'already running' files are now stored in the db folder, meaning hydrus shouldn't have to write to anything but db dir and temp dir</li>
<li>'already running' files now delete themselves on program close if they can</li>
<li>the log directory is no longer needed</li>
<li>if there is only one booru to select, it will be auto-selected</li>
<li>client failed exit is less likely to hang, more likely to log error</li>
<li>client won't bother to save lest session regularly or on exit if this is not the default startup session</li>
<li>hotfixed an auto-vacuum bug</li>
<li>added a catch for any future vacuum mess-ups to save the db from collapse</li>
<li>added other catches for other close/reinit db calls</li>
<li>misc cleanup</li>
</ul>
<li><h3>version 209</h3></li>
<ul>
<li>the advanced content update dialog can now be !aunched from manage tags, and will only affect the files the dialog was launched for</li>

View File

@ -139,7 +139,7 @@ class Controller( HydrusController.HydrusController ):
def CheckAlreadyRunning( self ):
while HydrusData.IsAlreadyRunning( 'client' ):
while HydrusData.IsAlreadyRunning( HC.DB_DIR, 'client' ):
self.pub( 'splash_set_status_text', 'client already running' )
@ -162,7 +162,7 @@ class Controller( HydrusController.HydrusController ):
for i in range( 10, 0, -1 ):
if not HydrusData.IsAlreadyRunning( 'client' ):
if not HydrusData.IsAlreadyRunning( HC.DB_DIR, 'client' ):
break
@ -616,6 +616,8 @@ class Controller( HydrusController.HydrusController ):
loaded_into_disk_cache = HydrusGlobals.client_controller.Read( 'load_into_disk_cache', stop_time = stop_time, caller_limit = 200 * 1024 * 1024 )
self.WriteInterruptable( 'vacuum', stop_time = stop_time )
self.pub( 'splash_set_status_text', 'analyzing' )
@ -1038,7 +1040,7 @@ class Controller( HydrusController.HydrusController ):
self.CheckAlreadyRunning()
HydrusData.RecordRunningStart( 'client' )
HydrusData.RecordRunningStart( HC.DB_DIR, 'client' )
self.InitModel()
@ -1085,6 +1087,8 @@ class Controller( HydrusController.HydrusController ):
self.ShutdownModel()
HydrusData.CleanRunningFile( HC.DB_DIR, 'client' )
except HydrusExceptions.PermissionException: pass
except HydrusExceptions.ShutdownException: pass
except:

View File

@ -27,6 +27,7 @@ import HydrusThreading
import ClientConstants as CC
import lz4
import os
import psutil
import Queue
import random
import shutil
@ -3963,14 +3964,13 @@ class DB( HydrusDB.HydrusDB ):
current_file_service_keys_to_timestamps = { service_ids_to_service_keys[ service_id ] : timestamp for ( service_id, timestamp ) in hash_ids_to_current_file_service_ids_and_timestamps[ hash_id ] }
file_service_keys_cdpp = ClientMedia.LocationsManager( current_file_service_keys, deleted_file_service_keys, pending_file_service_keys, petitioned_file_service_keys, urls = urls, service_keys_to_filenames = service_keys_to_filenames, current_to_timestamps = current_file_service_keys_to_timestamps )
locations_manager = ClientMedia.LocationsManager( current_file_service_keys, deleted_file_service_keys, pending_file_service_keys, petitioned_file_service_keys, urls = urls, service_keys_to_filenames = service_keys_to_filenames, current_to_timestamps = current_file_service_keys_to_timestamps )
#
local_ratings = { service_ids_to_service_keys[ service_id ] : rating for ( service_id, rating ) in hash_ids_to_local_ratings[ hash_id ] }
local_ratings = ClientRatings.LocalRatingsManager( local_ratings )
remote_ratings = {}
ratings_manager = ClientRatings.RatingsManager( local_ratings )
#
@ -3983,7 +3983,7 @@ class DB( HydrusDB.HydrusDB ):
( size, mime, width, height, duration, num_frames, num_words ) = ( None, HC.APPLICATION_UNKNOWN, None, None, None, None, None )
media_results.append( ClientMedia.MediaResult( ( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, file_service_keys_cdpp, local_ratings, remote_ratings ) ) )
media_results.append( ClientMedia.MediaResult( ( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, ratings_manager ) ) )
return media_results
@ -5036,6 +5036,11 @@ class DB( HydrusDB.HydrusDB ):
archives_dir = os.path.join( self._db_dir, 'client_archives' )
if not os.path.exists( archives_dir ):
os.makedirs( archives_dir )
for filename in os.listdir( archives_dir ):
if filename.endswith( '.db' ):
@ -5061,6 +5066,14 @@ class DB( HydrusDB.HydrusDB ):
def _InitCaches( self ):
HydrusGlobals.client_controller.pub( 'splash_set_status_text', 'preparing disk cache' )
stop_time = HydrusData.GetNow() + 10
self._LoadIntoDiskCache( stop_time = stop_time )
HydrusGlobals.client_controller.pub( 'splash_set_status_text', 'preparing db caches' )
self._local_file_service_id = self._GetServiceId( CC.LOCAL_FILE_SERVICE_KEY )
self._trash_service_id = self._GetServiceId( CC.TRASH_SERVICE_KEY )
self._local_tag_service_id = self._GetServiceId( CC.LOCAL_TAG_SERVICE_KEY )
@ -5127,24 +5140,61 @@ class DB( HydrusDB.HydrusDB ):
def _LoadIntoDiskCache( self ):
def _LoadIntoDiskCache( self, stop_time = None, caller_limit = None ):
self._CloseDBCursor()
for filename in self._db_filenames.values():
try:
path = os.path.join( self._db_dir, filename )
approx_disk_cache_size = psutil.virtual_memory().available * 4 / 5
with open( path, 'rb' ) as f:
while f.read( HC.READ_BLOCK_SIZE ) != '':
pass
disk_cache_limit = approx_disk_cache_size * 2 / 3
except psutil.Error:
disk_cache_limit = 1024 * 1024 * 1024
self._InitDBCursor()
so_far_read = 0
try:
paths = [ os.path.join( HC.DB_DIR, filename ) for filename in self._db_filenames.values() ]
paths.sort( key = os.path.getsize )
for path in paths:
with open( path, 'rb' ) as f:
while f.read( HC.READ_BLOCK_SIZE ) != '':
if stop_time is not None and HydrusData.TimeHasPassed( stop_time ):
return False
so_far_read += HC.READ_BLOCK_SIZE
if so_far_read > disk_cache_limit:
return True
if caller_limit is not None and so_far_read > caller_limit:
return False
finally:
self._InitDBCursor()
return True
def _MaintenanceDue( self ):
@ -6436,214 +6486,6 @@ class DB( HydrusDB.HydrusDB ):
self._controller.pub( 'splash_set_title_text', 'updating db to v' + str( version + 1 ) )
if version == 150:
options = self._GetOptions()
options[ 'file_system_predicates' ][ 'hamming_distance' ] = 5
self._c.execute( 'UPDATE options SET options = ?;', ( options, ) )
if version == 151:
results = self._c.execute( 'SELECT * FROM yaml_dumps WHERE dump_type = ?;', ( YAML_DUMP_ID_SUBSCRIPTION, ) ).fetchall()
for ( dump_type, dump_name, dump ) in results:
dump[ 'initial_limit' ] = 500
self._c.execute( 'UPDATE yaml_dumps SET dump = ? WHERE dump_type = ? and dump_name = ?;', ( dump, dump_type, dump_name ) )
if version == 152:
options = self._GetOptions()
options[ 'file_system_predicates' ][ 'num_pixels' ] = ( 1, 2, 2 )
self._c.execute( 'UPDATE options SET options = ?;', ( options, ) )
if version == 153:
options = self._GetOptions()
options[ 'file_system_predicates' ] = ClientDefaults.GetClientDefaultOptions()[ 'file_system_predicates' ]
self._c.execute( 'UPDATE options SET options = ?;', ( options, ) )
#
self._c.execute( 'CREATE TABLE json_dumps ( dump_type INTEGER PRIMARY KEY, version INTEGER, dump BLOB_BYTES );' )
self._c.execute( 'CREATE TABLE json_dumps_named ( dump_type INTEGER, dump_name TEXT, version INTEGER, dump BLOB_BYTES, PRIMARY KEY ( dump_type, dump_name ) );' )
#
results = self._c.execute( 'SELECT * FROM yaml_dumps WHERE dump_type = ?;', ( YAML_DUMP_ID_FAVOURITE_CUSTOM_FILTER_ACTIONS, ) ).fetchall()
objs = []
for ( dump_type, dump_name, dump ) in results:
shortcuts = ClientData.Shortcuts( dump_name )
actions = dump
for ( modifier, key, service_key, data ) in actions:
if isinstance( service_key, ClientData.ClientServiceIdentifier ): service_key = service_key.GetServiceKey()
action = ( service_key, data )
shortcuts.SetKeyboardAction( modifier, key, action )
objs.append( shortcuts )
for obj in objs:
( dump_type, dump_name, dump_version, serialisable_info ) = obj.GetSerialisableTuple()
dump = json.dumps( serialisable_info )
self._c.execute( 'INSERT INTO json_dumps_named ( dump_type, dump_name, version, dump ) VALUES ( ?, ?, ?, ? );', ( dump_type, dump_name, dump_version, sqlite3.Binary( dump ) ) )
self._c.execute( 'DELETE FROM yaml_dumps WHERE dump_type = ?;', ( YAML_DUMP_ID_FAVOURITE_CUSTOM_FILTER_ACTIONS, ) )
if version == 156:
results = self._c.execute( 'SELECT dump_type, dump_name, dump FROM json_dumps_named;' ).fetchall()
for ( dump_type, dump_name, dump ) in results:
try:
dump = lz4.loads( dump )
self._c.execute( 'UPDATE json_dumps_named SET dump = ? WHERE dump_type = ? AND dump_name = ?;', ( sqlite3.Binary( dump ), dump_type, dump_name ) )
except:
continue
if version == 157:
results = self._c.execute( 'SELECT * FROM yaml_dumps WHERE dump_type = ?;', ( YAML_DUMP_ID_SUBSCRIPTION, ) ).fetchall()
for ( dump_type, dump_name, dump ) in results:
dump[ 'get_tags_if_redundant' ] = False
a_i_o = dump[ 'advanced_import_options' ]
if 'auto_archive' not in a_i_o:
a_i_o[ 'auto_archive' ] = False
if 'exclude_deleted_files' not in a_i_o:
a_i_o[ 'exclude_deleted_files' ] = False
if 'min_resolution' not in a_i_o:
a_i_o[ 'min_resolution' ] = None
if 'min_size' not in a_i_o:
a_i_o[ 'min_size' ] = None
self._c.execute( 'UPDATE yaml_dumps SET dump = ? WHERE dump_type = ? and dump_name = ?;', ( dump, dump_type, dump_name ) )
#
results = self._c.execute( 'SELECT service_id, service_type, info FROM services WHERE service_type IN ( ?, ? );', ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ) ).fetchall()
for ( service_id, service_type, info ) in results:
if service_type == HC.LOCAL_RATING_LIKE:
del info[ 'like' ]
del info[ 'dislike' ]
info[ 'colours' ] = ClientRatings.default_like_colours
else:
upper = info[ 'upper' ]
lower = info[ 'lower' ]
del info[ 'upper' ]
del info[ 'lower' ]
info[ 'num_stars' ] = upper - lower
info[ 'colours' ] = ClientRatings.default_numerical_colours
info[ 'shape' ] = ClientRatings.CIRCLE
self._c.execute( 'UPDATE services SET info = ? WHERE service_id = ?;', ( info, service_id ) )
#
results = self._c.execute( 'SELECT * FROM yaml_dumps WHERE dump_type = ?;', ( YAML_DUMP_ID_EXPORT_FOLDER, ) ).fetchall()
for ( dump_type, dump_name, dump ) in results:
details = dump
details[ 'type' ] = HC.EXPORT_FOLDER_TYPE_REGULAR
self._c.execute( 'UPDATE yaml_dumps SET dump = ? WHERE dump_type = ? and dump_name = ?;', ( dump, dump_type, dump_name ) )
if version == 158:
results = self._c.execute( 'SELECT service_id, service_type, info FROM services WHERE service_type IN ( ?, ? );', ( HC.TAG_REPOSITORY, HC.FILE_REPOSITORY ) ).fetchall()
for ( service_id, service_type, info ) in results:
info[ 'first_timestamp' ] = None
info[ 'next_download_timestamp' ] = 0
self._c.execute( 'UPDATE services SET info = ? WHERE service_id = ?;', ( info, service_id ) )
for filename in os.listdir( HC.CLIENT_UPDATES_DIR ):
path = os.path.join( HC.CLIENT_UPDATES_DIR, filename )
ClientData.DeletePath( path )
if version == 159:
results = self._c.execute( 'SELECT service_id, service_type, info FROM services WHERE service_type = ?;', ( HC.LOCAL_RATING_NUMERICAL, ) ).fetchall()
for ( service_id, service_type, info ) in results:
info[ 'allow_zero' ] = True
self._c.execute( 'UPDATE services SET info = ? WHERE service_id = ?;', ( info, service_id ) )
if version == 160:
self._c.execute( 'REPLACE INTO yaml_dumps VALUES ( ?, ?, ? );', ( YAML_DUMP_ID_REMOTE_BOORU, 'e621', ClientDefaults.GetDefaultBoorus()[ 'e621' ] ) )
@ -7509,29 +7351,34 @@ class DB( HydrusDB.HydrusDB ):
self._CloseDBCursor()
for filename in self._db_filenames.values():
try:
self._controller.pub( 'splash_set_status_text', 'vacuuming ' + filename )
db_path = os.path.join( self._db_dir, filename )
try:
for filename in self._db_filenames.values():
if HydrusDB.CanVacuum( db_path ):
self._controller.pub( 'splash_set_status_text', 'vacuuming ' + filename )
db_path = os.path.join( self._db_dir, filename )
try:
HydrusDB.VacuumDB( db_path )
if HydrusDB.CanVacuum( db_path ):
HydrusDB.VacuumDB( db_path )
except Exception as e:
HydrusData.Print( 'Vacuum failed!' )
HydrusData.PrintException( e )
except Exception as e:
HydrusData.Print( 'Vacuum failed!' )
HydrusData.PrintException( e )
self._InitDBCursor()
self._c.execute( 'BEGIN IMMEDIATE;' )
finally:
self._InitDBCursor()
self._c.execute( 'BEGIN IMMEDIATE;' )
@ -7787,29 +7634,34 @@ class DB( HydrusDB.HydrusDB ):
self._CloseDBCursor()
for filename in self._db_filenames.values():
try:
self._controller.pub( 'splash_set_status_text', 'vacuuming ' + filename )
db_path = os.path.join( self._db_dir, filename )
try:
for filename in self._db_filenames.values():
if HydrusDB.CanVacuum( db_path ):
self._controller.pub( 'splash_set_status_text', 'vacuuming ' + filename )
db_path = os.path.join( self._db_dir, filename )
try:
HydrusDB.VacuumDB( db_path )
if HydrusDB.CanVacuum( db_path ):
HydrusDB.VacuumDB( db_path )
except Exception as e:
HydrusData.Print( 'Vacuum failed!' )
HydrusData.PrintException( e )
except Exception as e:
HydrusData.Print( 'Vacuum failed!' )
HydrusData.PrintException( e )
self._InitDBCursor()
self._c.execute( 'BEGIN IMMEDIATE;' )
finally:
self._InitDBCursor()
self._c.execute( 'BEGIN IMMEDIATE;' )
if version == 204:
@ -7913,6 +7765,47 @@ class DB( HydrusDB.HydrusDB ):
if version == 209:
update_dirnames = os.listdir( HC.CLIENT_UPDATES_DIR )
for update_dirname in update_dirnames:
update_dir = os.path.join( HC.CLIENT_UPDATES_DIR, update_dirname )
if os.path.isdir( update_dir ):
update_filenames = os.listdir( update_dir )
for update_filename in update_filenames:
update_path = os.path.join( update_dir, update_filename )
try:
with open( update_path, 'rb' ) as f:
content = f.read()
obj = HydrusSerialisable.CreateFromString( content )
compressed_content = obj.DumpToNetworkString()
with open( update_path, 'wb' ) as f:
f.write( compressed_content )
except:
HydrusData.Print( 'The path ' + update_path + ' failed to convert to a network string.' )
self._controller.pub( 'splash_set_title_text', 'updated db to v' + str( version + 1 ) )
self._c.execute( 'UPDATE version SET version = ?;', ( version + 1, ) )

View File

@ -728,7 +728,7 @@ class Imageboard( HydrusData.HydrusYAMLBase ):
def IsOkToPost( self, media_result ):
( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, local_ratings, remote_ratings ) = media_result.ToTuple()
( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, ratings_manager ) = media_result.ToTuple()
if CC.RESTRICTION_MIN_RESOLUTION in self._restrictions:
@ -1529,7 +1529,7 @@ class ServiceRepository( ServiceRestricted ):
content_update_package = self.Request( HC.GET, 'content_update_package', { 'begin' : begin, 'subindex' : subindex } )
obj_string = content_update_package.DumpToString()
obj_string = content_update_package.DumpToNetworkString()
job_key.SetVariable( 'popup_text_1', update_index_string + subupdate_index_string + 'saving to disk' )
@ -1541,7 +1541,7 @@ class ServiceRepository( ServiceRestricted ):
path = ClientFiles.GetExpectedServiceUpdatePackagePath( self._service_key, begin )
obj_string = service_update_package.DumpToString()
obj_string = service_update_package.DumpToNetworkString()
with open( path, 'wb' ) as f: f.write( obj_string )
@ -1578,6 +1578,33 @@ class ServiceRepository( ServiceRestricted ):
if self.CanProcessUpdate():
HydrusGlobals.client_controller.pub( 'splash_set_status_text', 'preparing disk cache' )
job_key.SetVariable( 'popup_text_1', 'preparing disk cache' )
loaded_into_disk_cache = False
while not loaded_into_disk_cache:
if options[ 'pause_repo_sync' ]:
break
( i_paused, should_quit ) = job_key.WaitIfNeeded()
if should_quit:
break
stop_time = HydrusData.GetNow() + 15
loaded_into_disk_cache = HydrusGlobals.client_controller.Read( 'load_into_disk_cache', stop_time = stop_time )
while self.CanProcessUpdate():
if options[ 'pause_repo_sync' ]:
@ -1618,7 +1645,7 @@ class ServiceRepository( ServiceRestricted ):
try:
service_update_package = HydrusSerialisable.CreateFromString( obj_string )
service_update_package = HydrusSerialisable.CreateFromNetworkString( obj_string )
if not isinstance( service_update_package, HydrusData.ServerToClientServiceUpdatePackage ):
@ -1673,7 +1700,7 @@ class ServiceRepository( ServiceRestricted ):
try:
content_update_package = HydrusSerialisable.CreateFromString( obj_string )
content_update_package = HydrusSerialisable.CreateFromNetworkString( obj_string )
if not isinstance( content_update_package, HydrusData.ServerToClientContentUpdatePackage ):
@ -2304,32 +2331,4 @@ def GetShortcutFromEvent( event ):
key = event.KeyCode
return ( modifier, key )
class ClientServiceIdentifier( HydrusData.HydrusYAMLBase ):
yaml_tag = u'!ClientServiceIdentifier'
def __init__( self, service_key, service_type, name ):
HydrusData.HydrusYAMLBase.__init__( self )
self._service_key = service_key
self._type = service_type
self._name = name
def __eq__( self, other ): return self.__hash__() == other.__hash__()
def __hash__( self ): return self._service_key.__hash__()
def __ne__( self, other ): return self.__hash__() != other.__hash__()
def __repr__( self ): return 'Client Service Identifier: ' + HydrusData.ToUnicode( ( self._name, HC.service_string_lookup[ self._type ] ) )
def GetInfo( self ): return ( self._service_key, self._type, self._name )
def GetName( self ): return self._name
def GetServiceKey( self ): return self._service_key
def GetServiceType( self ): return self._type

View File

@ -1163,7 +1163,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'debug_garbage' ), p( 'Garbage' ) )
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'clear_caches' ), p( '&Clear Preview/Fullscreen Caches' ) )
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'delete_service_info' ), p( '&Clear DB Service Info Cache' ), p( 'Delete all cached service info, in case it has become desynchronised.' ) )
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'load_into_disk_cache' ), p( 'Engage Turbo Mode (testing)' ) )
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'load_into_disk_cache' ), p( 'Load db into disk cache' ) )
menu.AppendMenu( wx.ID_NONE, p( 'Debug' ), debug )
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'help_shortcuts' ), p( '&Shortcuts' ) )
@ -2134,7 +2134,7 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
service.Request( HC.POST, 'file', { 'file' : file } )
( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, local_ratings, remote_ratings ) = media_result.ToTuple()
( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, ratings_manager ) = media_result.ToTuple()
timestamp = HydrusData.GetNow()
@ -2353,7 +2353,7 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
elif command == 'load_gui_session': self._LoadGUISession( data )
elif command == 'load_into_disk_cache':
self._controller.Read( 'load_into_disk_cache' )
self._controller.CallToThread( self._controller.Read, 'load_into_disk_cache' )
elif command == 'manage_account_types': self._ManageAccountTypes( data )
elif command == 'manage_boorus': self._ManageBoorus()
@ -2530,25 +2530,32 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
HydrusGlobals.restart = True
if not self._loading_session:
try:
self._SaveGUISession( 'last session' )
if HC.options[ 'default_gui_session' ] == 'last session' and not self._loading_session:
self._SaveGUISession( 'last session' )
self._message_manager.CleanBeforeDestroy()
self._message_manager.Hide()
for page in [ self._notebook.GetPage( i ) for i in range( self._notebook.GetPageCount() ) ]: page.CleanBeforeDestroy()
page = self._notebook.GetCurrentPage()
if page is not None:
self._message_manager.CleanBeforeDestroy()
( HC.options[ 'hpos' ], HC.options[ 'vpos' ] ) = page.GetSashPositions()
self._message_manager.Hide()
for page in [ self._notebook.GetPage( i ) for i in range( self._notebook.GetPageCount() ) ]: page.CleanBeforeDestroy()
page = self._notebook.GetCurrentPage()
if page is not None:
( HC.options[ 'hpos' ], HC.options[ 'vpos' ] ) = page.GetSashPositions()
self._controller.WriteSynchronous( 'save_options', HC.options )
except Exception as e:
HydrusData.PrintException( e )
self._controller.WriteSynchronous( 'save_options', HC.options )
self.Hide()
@ -2714,8 +2721,14 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
old_menu_index = self._menubar.FindMenu( old_label )
if show: self._menubar.Replace( old_menu_index, menu, label )
else: self._menubar.Remove( old_menu_index )
if show:
self._menubar.Replace( old_menu_index, menu, label )
else:
self._menubar.Remove( old_menu_index )
else:
@ -2729,7 +2742,10 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
( temp_menu, temp_label, temp_show ) = self._menus[ temp_name ]
if temp_show: insert_index += 1
if temp_show:
insert_index += 1
self._menubar.Insert( insert_index, menu, label )
@ -2745,7 +2761,10 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
def SaveLastSession( self ):
self._SaveGUISession( 'last session' )
if HC.options[ 'default_gui_session' ] == 'last session':
self._SaveGUISession( 'last session' )
wx.CallLater( 5 * 60 * 1000, self.SaveLastSession )

View File

@ -1431,8 +1431,6 @@ class CanvasWithDetails( Canvas ):
# ratings
( local_ratings, remote_ratings ) = self._current_display_media.GetRatings()
services_manager = HydrusGlobals.client_controller.GetServicesManager()
like_services = services_manager.GetServices( ( HC.LOCAL_RATING_LIKE, ), randomised = False )
@ -1454,7 +1452,6 @@ class CanvasWithDetails( Canvas ):
if len( like_services ) > 0: current_y += 20
numerical_services = services_manager.GetServices( ( HC.LOCAL_RATING_NUMERICAL, ), randomised = False )
for numerical_service in numerical_services:

View File

@ -580,7 +580,7 @@ class DialogAdvancedContentUpdate( Dialog ):
class DialogButtonChoice( Dialog ):
def __init__( self, parent, intro, choices ):
def __init__( self, parent, intro, choices, show_always_checkbox = False ):
Dialog.__init__( self, parent, 'choose what to do', position = 'center' )
@ -600,11 +600,23 @@ class DialogButtonChoice( Dialog ):
i += 1
self._always_do_checkbox = wx.CheckBox( self, label = 'do this for all' )
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( wx.StaticText( self, label = intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
for button in self._buttons: vbox.AddF( button, CC.FLAGS_EXPAND_PERPENDICULAR )
for button in self._buttons:
vbox.AddF( button, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._always_do_checkbox, CC.FLAGS_LONE_BUTTON )
if not show_always_checkbox:
self._always_do_checkbox.Hide()
self.SetSizer( vbox )
@ -630,7 +642,10 @@ class DialogButtonChoice( Dialog ):
def GetData( self ): return self._data
def GetData( self ):
return ( self._always_do_checkbox.GetValue(), self._data )
class DialogChooseNewServiceMethod( Dialog ):
@ -3877,7 +3892,16 @@ class DialogSelectBooru( Dialog ):
self.SetInitialSize( ( x, y ) )
wx.CallAfter( self._ok.SetFocus )
if len( boorus ) == 1:
self._boorus.Select( 0 )
wx.CallAfter( self.EventOK, None )
else:
wx.CallAfter( self._ok.SetFocus )
def EventDoubleClick( self, event ): self.EndModal( wx.ID_OK )
@ -4166,7 +4190,10 @@ class DialogSelectFromListOfStrings( Dialog ):
selection = self._strings.GetSelection()
if selection != wx.NOT_FOUND: self.EndModal( wx.ID_OK )
if selection != wx.NOT_FOUND:
self.EndModal( wx.ID_OK )
def EventSelect( self, event ): self.EndModal( wx.ID_OK )

View File

@ -9010,13 +9010,18 @@ class DialogManageTags( ClientGUIDialogs.Dialog ):
self._file_service_key = file_service_key
self._hashes = set()
self._canvas_key = canvas_key
self._current_media = media
media = ClientMedia.FlattenMedia( media )
for m in media: self._hashes.update( m.GetHashes() )
self._current_media = [ m.Duplicate() for m in media ]
self._hashes = set()
for m in self._current_media:
self._hashes.update( m.GetHashes() )
( remember, position ) = HC.options[ 'tag_dialog_position' ]
@ -9065,7 +9070,7 @@ class DialogManageTags( ClientGUIDialogs.Dialog ):
service_type = service.GetServiceType()
name = service.GetName()
page = self._Panel( self._tag_repositories, self._file_service_key, service.GetServiceKey(), media )
page = self._Panel( self._tag_repositories, self._file_service_key, service.GetServiceKey(), self._current_media )
self._tag_repositories.AddPage( name, service_key, page )
@ -9531,30 +9536,61 @@ class DialogManageTags( ClientGUIDialogs.Dialog ):
forced_choice_actions = []
for choices in sets_of_choices:
always_do = False
if len( choices ) == 1:
[ ( text_gumpf, choice ) ] = choices
else:
intro = 'What would you like to do?'
choice = None
with ClientGUIDialogs.DialogButtonChoice( self, intro, choices ) as dlg:
for forced_choice_action in forced_choice_actions:
result = dlg.ShowModal()
for possible_choice in choices:
( text_gumpf, ( choice_action, choice_tag ) ) = possible_choice
if choice_action == forced_choice_action:
choice = ( choice_action, choice_tag )
break
if result == wx.ID_OK:
choice = dlg.GetData()
else:
if choice is not None:
break
if choice is None:
intro = 'What would you like to do?'
show_always_checkbox = len( sets_of_choices ) > 1
with ClientGUIDialogs.DialogButtonChoice( self, intro, choices, show_always_checkbox = show_always_checkbox ) as dlg:
result = dlg.ShowModal()
if result == wx.ID_OK:
( always_do, choice ) = dlg.GetData()
else:
break
if choice is None:
@ -9563,6 +9599,11 @@ class DialogManageTags( ClientGUIDialogs.Dialog ):
( choice_action, choice_tag ) = choice
if always_do:
forced_choice_actions.append( choice_action )
if choice_action == HC.CONTENT_UPDATE_ADD: media_to_affect = ( m for m in self._media if choice_tag not in m.GetTagsManager().GetCurrent( self._tag_service_key ) )
elif choice_action == HC.CONTENT_UPDATE_DELETE: media_to_affect = ( m for m in self._media if choice_tag in m.GetTagsManager().GetCurrent( self._tag_service_key ) )
elif choice_action == HC.CONTENT_UPDATE_PEND: media_to_affect = ( m for m in self._media if choice_tag not in m.GetTagsManager().GetCurrent( self._tag_service_key ) and choice_tag not in m.GetTagsManager().GetPending( self._tag_service_key ) )
@ -9745,15 +9786,12 @@ class DialogManageTags( ClientGUIDialogs.Dialog ):
self._content_updates = []
if media is None: media = []
if media is None:
media = []
hashes = { hash for hash in itertools.chain.from_iterable( ( m.GetHashes() for m in media ) ) }
if len( hashes ) > 0: media_results = HydrusGlobals.client_controller.Read( 'media_results', hashes )
else: media_results = []
# this should now be a nice clean copy of the original media
self._media = [ ClientMedia.MediaSingleton( media_result ) for media_result in media_results ]
self._media = media
self._tags_box.SetTagsByMedia( self._media )

View File

@ -18,6 +18,24 @@ import HydrusExceptions
import HydrusGlobals
import itertools
def FlattenMedia( media_list ):
flat_media = []
for media in media_list:
if media.IsCollection():
flat_media.extend( media.GetFlatMedia() )
else:
flat_media.append( media )
return flat_media
def MergeTagsManagers( tags_managers ):
def CurrentAndPendingFilter( items ):
@ -99,6 +117,19 @@ class LocationsManager( object ):
self._petitioned.discard( service_key )
def Duplicate( self ):
current = set( self._current )
deleted = set( self._deleted )
pending = set( self._pending )
petitioned = set( self._petitioned )
urls = list( self._urls )
service_keys_to_filenames = dict( self._service_keys_to_filenames )
current_to_timestamps = dict( self._current_to_timestamps )
return LocationsManager( current, deleted, pending, petitioned, urls = urls, service_keys_to_filenames = service_keys_to_filenames, current_to_timestamps = current_to_timestamps )
def GetCDPP( self ): return ( self._current, self._deleted, self._pending, self._petitioned )
def GetCurrent( self ): return self._current
@ -298,29 +329,27 @@ class MediaList( object ):
services_manager = HydrusGlobals.client_controller.GetServicesManager()
local_ratings_to_collect_by = [ service_key for service_key in ratings_to_collect_by if services_manager.GetService( service_key ).GetServiceType() in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ) ]
remote_ratings_to_collect_by = [ service_key for service_key in ratings_to_collect_by if services_manager.GetService( service_key ).GetServiceType() in ( HC.RATING_LIKE_REPOSITORY, HC.RATING_NUMERICAL_REPOSITORY ) ]
keys_to_medias = collections.defaultdict( list )
for media in medias:
if len( namespaces_to_collect_by ) > 0: namespace_key = media.GetTagsManager().GetNamespaceSlice( namespaces_to_collect_by, collapse_siblings = True )
else: namespace_key = None
if len( namespaces_to_collect_by ) > 0:
namespace_key = media.GetTagsManager().GetNamespaceSlice( namespaces_to_collect_by, collapse_siblings = True )
else:
namespace_key = None
if len( ratings_to_collect_by ) > 0:
( local_ratings, remote_ratings ) = media.GetRatings()
rating_key = media.GetRatingsManager().GetRatingSlice( ratings_to_collect_by )
if len( local_ratings_to_collect_by ) > 0: local_rating_key = local_ratings.GetRatingSlice( local_ratings_to_collect_by )
else: local_rating_key = None
else:
if len( remote_ratings_to_collect_by ) > 0: remote_rating_key = remote_ratings.GetRatingSlice( remote_ratings_to_collect_by )
else: remote_rating_key = None
rating_key = None
rating_key = ( local_rating_key, remote_rating_key )
else: rating_key = None
keys_to_medias[ ( namespace_key, rating_key ) ].append( media )
@ -566,9 +595,12 @@ class MediaList( object ):
if unrated is not None:
( local_ratings, remote_ratings ) = media.GetRatings()
ratings_manager = media.GetRatingsManager()
if local_ratings.GetRating( unrated ) is not None: continue
if ratings_manager.GetRating( unrated ) is not None:
continue
if for_media_viewer:
@ -731,14 +763,14 @@ class MediaList( object ):
def ratings_sort_function( service_key, reverse, x ):
( x_local_ratings, x_remote_ratings ) = x.GetRatings()
x_ratings_manager = x.GetRatingsManager()
service = HydrusGlobals.client_controller.GetServicesManager().GetService( service_key )
rating = deal_with_none( x_ratings_manager.GetRating( service_key ) )
if service.GetServiceType() in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): rating = deal_with_none( x_local_ratings.GetRating( service_key ) )
else: rating = deal_with_none( x_remote_ratings.GetScore( service_key ) )
if reverse: rating *= -1
if reverse:
rating *= -1
return rating
@ -830,8 +862,14 @@ class MediaCollection( MediaList, Media ):
self._tags_manager = MergeTagsManagers( tags_managers )
# horrible compromise
if len( self._sorted_media ) > 0: self._ratings = self._sorted_media[0].GetRatings()
else: self._ratings = ( ClientRatings.LocalRatingsManager( {} ), ClientRatings.CPRemoteRatingsServiceKeys( {} ) )
if len( self._sorted_media ) > 0:
self._ratings_manager = self._sorted_media[0].GetRatingsManager()
else:
self._ratings_manager = ClientRatings.RatingsManager( {} )
all_locations_managers = [ media.GetLocationsManager() for media in self._sorted_media ]
@ -916,7 +954,10 @@ class MediaCollection( MediaList, Media ):
return [ info_string ]
def GetRatings( self ): return self._ratings
def GetRatingsManager( self ):
return self._ratings_manager
def GetResolution( self ): return ( self._width, self._height )
@ -974,6 +1015,11 @@ class MediaSingleton( Media ):
self._media_result = media_result
def Duplicate( self ):
return MediaSingleton( self._media_result.Duplicate() )
def GetDisplayMedia( self ): return self
def GetDuration( self ): return self._media_result.GetDuration()
@ -1070,7 +1116,7 @@ class MediaSingleton( Media ):
def GetPrettyInfoLines( self ):
( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, local_ratings, remote_ratings ) = self._media_result.ToTuple()
( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, ratings_manager ) = self._media_result.ToTuple()
info_string = HydrusData.ConvertIntToBytes( size ) + ' ' + HC.mime_string_lookup[ mime ]
@ -1130,7 +1176,7 @@ class MediaSingleton( Media ):
return lines
def GetRatings( self ): return self._media_result.GetRatings()
def GetRatingsManager( self ): return self._media_result.GetRatingsManager()
def GetResolution( self ):
@ -1275,14 +1321,14 @@ class MediaResult( object ):
def __init__( self, tuple ):
# hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, local_ratings, remote_ratings
# hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, ratings_manager
self._tuple = tuple
def DeletePending( self, service_key ):
( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, local_ratings, remote_ratings ) = self._tuple
( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, ratings_manager ) = self._tuple
service = HydrusGlobals.client_controller.GetServicesManager().GetService( service_key )
@ -1292,6 +1338,19 @@ class MediaResult( object ):
elif service_type in ( HC.FILE_REPOSITORY, HC.LOCAL_FILE ): locations_manager.DeletePending( service_key )
def Duplicate( self ):
( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, ratings_manager ) = self._tuple
tags_manager = tags_manager.Duplicate()
locations_manager = locations_manager.Duplicate()
ratings_manager = ratings_manager.Duplicate()
tuple = ( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, ratings_manager )
return MediaResult( tuple )
def GetHash( self ): return self._tuple[0]
def GetDuration( self ): return self._tuple[6]
@ -1306,7 +1365,7 @@ class MediaResult( object ):
def GetNumWords( self ): return self._tuple[8]
def GetRatings( self ): return ( self._tuple[11], self._tuple[12] )
def GetRatingsManager( self ): return self._tuple[11]
def GetResolution( self ): return ( self._tuple[4], self._tuple[5] )
@ -1318,19 +1377,28 @@ class MediaResult( object ):
( data_type, action, row ) = content_update.ToTuple()
( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, local_ratings, remote_ratings ) = self._tuple
( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, ratings_manager ) = self._tuple
service = HydrusGlobals.client_controller.GetServicesManager().GetService( service_key )
service_type = service.GetServiceType()
if service_type in HC.TAG_SERVICES: tags_manager.ProcessContentUpdate( service_key, content_update )
if service_type in HC.TAG_SERVICES:
tags_manager.ProcessContentUpdate( service_key, content_update )
elif service_type in ( HC.FILE_REPOSITORY, HC.LOCAL_FILE, HC.IPFS ):
if service_type == HC.LOCAL_FILE:
if action == HC.CONTENT_UPDATE_ARCHIVE: inbox = False
elif action == HC.CONTENT_UPDATE_INBOX: inbox = True
if action == HC.CONTENT_UPDATE_ARCHIVE:
inbox = False
elif action == HC.CONTENT_UPDATE_INBOX:
inbox = True
if service_key == CC.LOCAL_FILE_SERVICE_KEY:
@ -1347,21 +1415,20 @@ class MediaResult( object ):
self._tuple = ( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, local_ratings, remote_ratings )
self._tuple = ( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, ratings_manager )
locations_manager.ProcessContentUpdate( service_key, content_update )
elif service_type in HC.RATINGS_SERVICES:
if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): local_ratings.ProcessContentUpdate( service_key, content_update )
else: remote_ratings.ProcessContentUpdate( service_key, content_update )
ratings_manager.ProcessContentUpdate( service_key, content_update )
def ResetService( self, service_key ):
( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, local_ratings, remote_ratings ) = self._tuple
( hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, ratings_manager ) = self._tuple
tags_manager.ResetService( service_key )
locations_manager.ResetService( service_key )
@ -1502,6 +1569,25 @@ class TagsManagerSimple( object ):
self._combined_namespaces_cache = None
def Duplicate( self ):
dupe_service_keys_to_statuses_to_tags = collections.defaultdict( HydrusData.default_dict_set )
for ( service_key, statuses_to_tags ) in self._service_keys_to_statuses_to_tags.items():
dupe_statuses_to_tags = HydrusData.default_dict_set()
for ( status, tags ) in statuses_to_tags.items():
dupe_statuses_to_tags[ status ] = set( tags )
dupe_service_keys_to_statuses_to_tags[ service_key ] = dupe_statuses_to_tags
return TagsManagerSimple( dupe_service_keys_to_statuses_to_tags )
def GetCombinedNamespaces( self, namespaces ):
if self._combined_namespaces_cache is None:
@ -1612,6 +1698,25 @@ class TagsManager( TagsManagerSimple ):
def Duplicate( self ):
dupe_service_keys_to_statuses_to_tags = collections.defaultdict( HydrusData.default_dict_set )
for ( service_key, statuses_to_tags ) in self._service_keys_to_statuses_to_tags.items():
dupe_statuses_to_tags = HydrusData.default_dict_set()
for ( status, tags ) in statuses_to_tags.items():
dupe_statuses_to_tags[ status ] = set( tags )
dupe_service_keys_to_statuses_to_tags[ service_key ] = dupe_statuses_to_tags
return TagsManager( dupe_service_keys_to_statuses_to_tags )
def GetCurrent( self, service_key = CC.COMBINED_TAG_SERVICE_KEY ):
statuses_to_tags = self._service_keys_to_statuses_to_tags[ service_key ]

View File

@ -100,13 +100,22 @@ def GetLikeStateFromMedia( media, service_key ):
for m in media:
( local_ratings, remote_ratings ) = m.GetRatings()
ratings_manager = m.GetRatingsManager()
rating = local_ratings.GetRating( service_key )
rating = ratings_manager.GetRating( service_key )
if rating == 1: on_exists = True
elif rating == 0: off_exists = True
elif rating is None: null_exists = True
if rating == 1:
on_exists = True
elif rating == 0:
off_exists = True
elif rating is None:
null_exists = True
if len( [ b for b in ( on_exists, off_exists, null_exists ) if b ] ) == 1:
@ -130,9 +139,9 @@ def GetNumericalStateFromMedia( media, service_key ):
for m in media:
( local_ratings, remote_ratings ) = m.GetRatings()
ratings_manager = m.GetRatingsManager()
rating = local_ratings.GetRating( service_key )
rating = ratings_manager.GetRating( service_key )
if rating is None:
@ -248,83 +257,28 @@ def GetStars( service_key, rating_state, rating ):
return ( shape, stars )
class CPRemoteRatingsServiceKeys( object ):
def __init__( self, service_keys_to_cp ):
self._service_keys_to_cp = service_keys_to_cp
def GetCP( self, service_key ):
if service_key in self._service_keys_to_cp: return self._service_keys_to_cp[ service_key ]
else: return ( None, None )
def GetRatingSlice( self, service_keys ):
# this doesn't work yet. it should probably use self.GetScore( service_key ) like I think Sort by remote rating does
return frozenset( { self._service_keys_to_cp[ service_key ] for service_key in service_keys if service_key in self._service_keys_to_cp } )
def GetServiceKeysToRatingsCP( self ): return self._service_keys_to_cp
def ProcessContentUpdate( self, service_key, content_update ):
( data_type, action, row ) = content_update.ToTuple()
if service_key in self._service_keys_to_cp: ( current, pending ) = self._service_keys_to_cp[ service_key ]
else:
( current, pending ) = ( None, None )
self._service_keys_to_cp[ service_key ] = ( current, pending )
# this may well need work; need to figure out how to set the pending back to None after an upload. rescind seems ugly
if action == HC.CONTENT_UPDATE_ADD:
rating = content_update.GetInfo()
current = rating
elif action == HC.CONTENT_UPDATE_DELETE:
current = None
elif action == HC.CONTENT_UPDATE_RESCIND_PEND:
pending = None
elif action == HC.CONTENT_UPDATE_DELETE:
rating = content_update.GetInfo()
pending = rating
def ResetService( self, service_key ):
if service_key in self._service_keys_to_cp:
( current, pending ) = self._service_keys_to_cp[ service_key ]
self._service_keys_to_cp[ service_key ] = ( None, None )
class LocalRatingsManager( object ):
class RatingsManager( object ):
def __init__( self, service_keys_to_ratings ):
self._service_keys_to_ratings = service_keys_to_ratings
def Duplicate( self ):
return RatingsManager( dict( self._service_keys_to_ratings ) )
def GetRating( self, service_key ):
if service_key in self._service_keys_to_ratings: return self._service_keys_to_ratings[ service_key ]
else: return None
if service_key in self._service_keys_to_ratings:
return self._service_keys_to_ratings[ service_key ]
else:
return None
def GetRatingSlice( self, service_keys ): return frozenset( { self._service_keys_to_ratings[ service_key ] for service_key in service_keys if service_key in self._service_keys_to_ratings } )

View File

@ -27,7 +27,6 @@ CLIENT_UPDATES_DIR = os.path.join( DB_DIR, 'client_updates' )
SERVER_UPDATES_DIR = os.path.join( DB_DIR, 'server_updates' )
HELP_DIR = os.path.join( BASE_DIR, 'help' )
INCLUDE_DIR = os.path.join( BASE_DIR, 'include' )
LOGS_DIR = os.path.join( BASE_DIR, 'logs' )
STATIC_DIR = os.path.join( BASE_DIR, 'static' )
#
@ -49,7 +48,7 @@ options = {}
# Misc
NETWORK_VERSION = 17
SOFTWARE_VERSION = 209
SOFTWARE_VERSION = 210
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )

View File

@ -56,6 +56,19 @@ def CalculateScoreFromRating( count, rating ):
return score
def CleanRunningFile( db_path, instance ):
path = os.path.join( db_path, instance + '_running' )
try:
os.remove( path )
except:
pass
def ConvertContentsToClientToServerContentUpdatePackage( action, contents, reason = None ):
hashes_to_hash_ids = {}
@ -636,9 +649,9 @@ def GetNowPrecise():
if HC.PLATFORM_WINDOWS: return time.clock()
else: return time.time()
def GetSiblingProcessPorts( instance ):
def GetSiblingProcessPorts( db_path, instance ):
path = os.path.join( HC.BASE_DIR, instance + '_running' )
path = os.path.join( db_path, instance + '_running' )
if os.path.exists( path ):
@ -727,9 +740,9 @@ def IntelligentMassIntersect( sets_to_reduce ):
if answer is None: return set()
else: return answer
def IsAlreadyRunning( instance ):
def IsAlreadyRunning( db_path, instance ):
path = os.path.join( HC.BASE_DIR, instance + '_running' )
path = os.path.join( db_path, instance + '_running' )
if os.path.exists( path ):
@ -870,9 +883,9 @@ def Profile( code, g, l ):
DebugPrint( output.read() )
def RecordRunningStart( instance ):
def RecordRunningStart( db_path, instance ):
path = os.path.join( HC.BASE_DIR, instance + '_running' )
path = os.path.join( db_path, instance + '_running' )
record_string = ''

View File

@ -8,9 +8,9 @@ import time
# I guess I am sending bad characters or something to the 'windowised' environment of pythonw
class HydrusLogger( object ):
def __init__( self, log_filename ):
def __init__( self, log_path ):
self._log_filename = log_filename
self._log_path = log_path
def __enter__( self ):
@ -23,7 +23,7 @@ class HydrusLogger( object ):
sys.stdout = self
sys.stderr = self
self._log_file = open( os.path.join( HC.LOGS_DIR, self._log_filename ), 'a' )
self._log_file = open( self._log_path, 'a' )
return self

View File

@ -38,7 +38,7 @@ def GetStartingAction():
else:
already_running = HydrusData.IsAlreadyRunning( 'server' )
already_running = HydrusData.IsAlreadyRunning( HC.DB_DIR, 'server' )
if command == 'start':
@ -77,7 +77,7 @@ def GetStartingAction():
else:
already_running = HydrusData.IsAlreadyRunning( 'server' )
already_running = HydrusData.IsAlreadyRunning( HC.DB_DIR, 'server' )
if not already_running:
@ -111,7 +111,7 @@ def ShutdownSiblingInstance():
port_found = False
ports = HydrusData.GetSiblingProcessPorts( 'server' )
ports = HydrusData.GetSiblingProcessPorts( HC.DB_DIR, 'server' )
if ports is None:
@ -164,7 +164,7 @@ def ShutdownSiblingInstance():
time_waited = 0
while HydrusData.IsAlreadyRunning( 'server' ):
while HydrusData.IsAlreadyRunning( HC.DB_DIR, 'server' ):
time.sleep( 1 )
@ -300,6 +300,8 @@ class Controller( HydrusController.HydrusController ):
self.ShutdownModel()
HydrusData.CleanRunningFile( HC.DB_DIR, 'server' )
def GetServerSessionManager( self ):
@ -356,7 +358,7 @@ class Controller( HydrusController.HydrusController ):
def Run( self ):
HydrusData.RecordRunningStart( 'server' )
HydrusData.RecordRunningStart( HC.DB_DIR, 'server' )
HydrusData.Print( 'Initialising db...' )

View File

@ -152,13 +152,7 @@ class DB( HydrusDB.HydrusDB ):
dest_path = ServerFiles.GetExpectedFilePath( hash )
with open( source_path, 'rb' ) as f_source:
with open( dest_path, 'wb' ) as f_dest:
HydrusPaths.CopyFileLikeToFileLike( f_source, f_dest )
HydrusPaths.MirrorFile( source_path, dest_path )
if 'thumbnail' in file_dict:
@ -2308,39 +2302,6 @@ class DB( HydrusDB.HydrusDB ):
HydrusData.Print( 'The server is updating to version ' + str( version + 1 ) )
if version == 155:
results = self._c.execute( 'SELECT service_id, account_type_id, account_type FROM account_types;' ).fetchall()
for ( service_id, account_type_id, account_type ) in results:
title = account_type.GetTitle()
self._c.execute( 'UPDATE account_types SET title = ? WHERE service_id = ? AND account_type_id = ?;', ( title, service_id, account_type_id ) )
if version == 158:
first_ends = self._c.execute( 'SELECT service_id, end FROM update_cache WHERE begin = ?;', ( 0, ) ).fetchall()
self._c.execute( 'DELETE FROM update_cache;' )
for filename in os.listdir( HC.SERVER_UPDATES_DIR ):
path = os.path.join( HC.SERVER_UPDATES_DIR, filename )
HydrusPaths.RecyclePath( path )
for ( service_id, end ) in first_ends:
service_key = self._GetServiceKey( service_id )
self._CreateUpdate( service_key, 0, end )
if version == 161:
for filename in os.listdir( HC.SERVER_UPDATES_DIR ):
@ -2555,21 +2516,26 @@ class DB( HydrusDB.HydrusDB ):
self._CloseDBCursor()
for filename in self._db_filenames.values():
try:
HydrusData.Print( 'vacuuming ' + filename )
db_path = os.path.join( self._db_dir, filename )
if HydrusDB.CanVacuum( db_path ):
for filename in self._db_filenames.values():
HydrusDB.VacuumDB( db_path )
HydrusData.Print( 'vacuuming ' + filename )
db_path = os.path.join( self._db_dir, filename )
if HydrusDB.CanVacuum( db_path ):
HydrusDB.VacuumDB( db_path )
self._InitDBCursor()
self._c.execute( 'BEGIN IMMEDIATE;' )
finally:
self._InitDBCursor()
self._c.execute( 'BEGIN IMMEDIATE;' )
if version == 202:

View File

@ -654,7 +654,7 @@ class TestClientDB( unittest.TestCase ):
( media_result, ) = self._read( 'media_results', ( written_hash, ) )
( mr_hash, mr_inbox, mr_size, mr_mime, mr_width, mr_height, mr_duration, mr_num_frames, mr_num_words, mr_tags_manager, mr_locations_manager, mr_local_ratings, mr_remote_ratings ) = media_result.ToTuple()
( mr_hash, mr_inbox, mr_size, mr_mime, mr_width, mr_height, mr_duration, mr_num_frames, mr_num_words, mr_tags_manager, mr_locations_manager, mr_ratings_manager ) = media_result.ToTuple()
now = HydrusData.GetNow()
@ -788,7 +788,7 @@ class TestClientDB( unittest.TestCase ):
( media_result, ) = self._read( 'media_results', ( hash, ) )
( mr_hash, mr_inbox, mr_size, mr_mime, mr_width, mr_height, mr_duration, mr_num_frames, mr_num_words, mr_tags_manager, mr_locations_manager, mr_local_ratings, mr_remote_ratings ) = media_result.ToTuple()
( mr_hash, mr_inbox, mr_size, mr_mime, mr_width, mr_height, mr_duration, mr_num_frames, mr_num_words, mr_tags_manager, mr_locations_manager, mr_ratings_manager ) = media_result.ToTuple()
now = HydrusData.GetNow()
@ -805,7 +805,7 @@ class TestClientDB( unittest.TestCase ):
( media_result, ) = self._read( 'media_results_from_ids', ( 1, ) )
( mr_hash, mr_inbox, mr_size, mr_mime, mr_width, mr_height, mr_duration, mr_num_frames, mr_num_words, mr_tags_manager, mr_locations_manager, mr_local_ratings, mr_remote_ratings ) = media_result.ToTuple()
( mr_hash, mr_inbox, mr_size, mr_mime, mr_width, mr_height, mr_duration, mr_num_frames, mr_num_words, mr_tags_manager, mr_locations_manager, mr_ratings_manager ) = media_result.ToTuple()
now = HydrusData.GetNow()

View File

@ -270,9 +270,9 @@ class TestServer( unittest.TestCase ):
info[ 'timeout' ] = 0
info[ 'hashes' ] = hashes
# hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, local_ratings, remote_ratings
# hash, inbox, size, mime, width, height, duration, num_frames, num_words, tags_manager, locations_manager, ratings_manager
media_results = [ ClientMedia.MediaResult( ( hash, True, 500, HC.IMAGE_JPEG, 640, 480, None, None, None, None, None, None, None ) ) for hash in hashes ]
media_results = [ ClientMedia.MediaResult( ( hash, True, 500, HC.IMAGE_JPEG, 640, 480, None, None, None, None, None, None ) ) for hash in hashes ]
HydrusGlobals.test_controller.SetRead( 'local_booru_share_keys', [ share_key ] )
HydrusGlobals.test_controller.SetRead( 'local_booru_share', info )

0
logs/.gitignore vendored
View File

View File

@ -43,7 +43,9 @@ try:
else:
with HydrusLogger.HydrusLogger( 'server.log' ) as logger:
log_path = os.path.join( HC.DB_DIR, 'server.log' )
with HydrusLogger.HydrusLogger( log_path ) as logger:
try: