Version 125

This commit is contained in:
Hydrus 2014-08-06 15:29:17 -05:00
parent 033829f432
commit 4125ced999
21 changed files with 712 additions and 402 deletions

View File

@ -8,6 +8,24 @@
<div class="content">
<h3>changelog</h3>
<ul>
<li><h3>version 125</h3></li>
<ul>
<li>moved client splash screen and client boot to application event loop (i.e. your mouse won't hourglass over it now)</li>
<li>splash screen is now draggable</li>
<li>added splash screen for client shutdown</li>
<li>cleaned up shutdown procedure</li>
<li>added detailed A/C timing options</li>
<li>created a new text entry dialog that won't allow ok on empty text</li>
<li>hence fixed a startup bug when a session was created with no name (and likely others!)</li>
<li>further tweaked idle calculation to improve maintenance routine</li>
<li>revised a bunch of the maintenance timer logic</li>
<li>fixed some bugs in the maintenance timer logic</li>
<li>fixed a daemon error reporting typo</li>
<li>fixed another way session data usage tracking could split, server-side</li>
<li>brushed some more dust off the server-side session code</li>
<li>improved some bad image processing nomenclature</li>
<li>took first steps in service_identifier replacement rewrite</li>
</ul>
<li><h3>version 124</h3></li>
<ul>
<li>fixed some more broken gifs (those with funky transparency, I think)</li>

View File

@ -191,6 +191,7 @@ CLIENT_DEFAULT_OPTIONS[ 'password' ] = None
CLIENT_DEFAULT_OPTIONS[ 'num_autocomplete_chars' ] = 2
CLIENT_DEFAULT_OPTIONS[ 'gui_capitalisation' ] = False
CLIENT_DEFAULT_OPTIONS[ 'default_gui_session' ] = 'just a blank page'
CLIENT_DEFAULT_OPTIONS[ 'ac_timings' ] = ( 3, 500, 250 )
system_predicates = {}
@ -2283,17 +2284,19 @@ class Service( HC.HydrusYAMLBase ):
yaml_tag = u'!Service'
def __init__( self, service_identifier, info ):
def __init__( self, service_key, service_type, name, info ):
HC.HydrusYAMLBase.__init__( self )
self._service_identifier = service_identifier
self._key = service_key
self._type = service_type
self._name = name
self._info = info
HC.pubsub.sub( self, 'ProcessServiceUpdates', 'service_updates_data' )
def __hash__( self ): return self._service_identifier.__hash__()
def __hash__( self ): return self._key.__hash__()
def CanDownload( self ): return self._info[ 'account' ].HasPermission( HC.GET_DATA ) and not self.HasRecentError()
@ -2326,20 +2329,26 @@ class Service( HC.HydrusYAMLBase ):
else: return self._info[ key ]
def GetKey( self ): return self._key
def GetLikeDislike( self ): return ( self._info[ 'like' ], self._info[ 'dislike' ] )
def GetLowerUpper( self ): return ( self._info[ 'lower' ], self._info[ 'upper' ] )
def GetName( self ): return self._name
def GetRecentErrorPending( self ):
if 'account' in self._info and self._info[ 'account' ].HasPermission( HC.GENERAL_ADMIN ): return HC.ConvertTimestampToPrettyPending( self._info[ 'last_error' ] + 600 )
else: return HC.ConvertTimestampToPrettyPending( self._info[ 'last_error' ] + 3600 * 4 )
def GetServiceIdentifier( self ): return self._service_identifier
def GetServiceIdentifier( self ): return HC.ClientServiceIdentifier( self._key, self._type, self._name )
def GetTimestamps( self ): return ( self._info[ 'first_timestamp' ], self._info[ 'next_download_timestamp' ], self._info[ 'next_processing_timestamp' ] )
def GetType( self ): return self._type
def GetUpdateStatus( self ):
account = self._info[ 'account' ]
@ -2384,9 +2393,7 @@ class Service( HC.HydrusYAMLBase ):
def IsInitialised( self ):
service_type = self._service_identifier.GetType()
if service_type == HC.SERVER_ADMIN: return 'access_key' in self._info
if self._type == HC.SERVER_ADMIN: return 'access_key' in self._info
else: return True
@ -2398,7 +2405,7 @@ class Service( HC.HydrusYAMLBase ):
for service_update in service_updates:
if service_identifier == self._service_identifier:
if service_identifier.GetServiceKey() == self._key:
( action, row ) = service_update.ToTuple()
@ -2420,9 +2427,7 @@ class Service( HC.HydrusYAMLBase ):
num_bytes = row
service_type = self._service_identifier.GetType()
if service_type == HC.LOCAL_BOORU:
if self._type == HC.LOCAL_BOORU:
self._info[ 'used_monthly_data' ] += num_bytes
self._info[ 'used_monthly_requests' ] += 1
@ -2462,7 +2467,7 @@ class Service( HC.HydrusYAMLBase ):
if command in ( 'access_key', 'init' ): pass
elif command in ( 'session_key', 'access_key_verification' ): HydrusNetworking.AddHydrusCredentialsToHeaders( credentials, request_headers )
else: HydrusNetworking.AddHydrusSessionKeyToHeaders( self._service_identifier, request_headers )
else: HydrusNetworking.AddHydrusSessionKeyToHeaders( self.GetServiceIdentifier(), request_headers )
if command == 'backup': long_timeout = True
else: long_timeout = False
@ -2506,12 +2511,12 @@ class Service( HC.HydrusYAMLBase ):
( response, size_of_response, response_headers, cookies ) = HC.http.Request( method, url, request_headers, body, report_hooks = report_hooks, response_to_path = response_to_path, return_everything = True, long_timeout = long_timeout )
HydrusNetworking.CheckHydrusVersion( self._service_identifier, response_headers )
HydrusNetworking.CheckHydrusVersion( self.GetServiceIdentifier(), response_headers )
if method == HC.GET: data_used = size_of_response
elif method == HC.POST: data_used = len( body )
HydrusNetworking.DoHydrusBandwidth( self._service_identifier, method, command, data_used )
HydrusNetworking.DoHydrusBandwidth( self.GetServiceIdentifier(), method, command, data_used )
if return_cookies: return ( response, cookies )
else: return response
@ -2524,15 +2529,15 @@ class Service( HC.HydrusYAMLBase ):
session_manager = HC.app.GetManager( 'hydrus_sessions' )
session_manager.DeleteSessionKey( self._service_identifier )
session_manager.DeleteSessionKey( self.GetServiceIdentifier() )
HC.app.Write( 'service_updates', { self._service_identifier : [ HC.ServiceUpdate( HC.SERVICE_UPDATE_ERROR, HC.u( e ) ) ] } )
HC.app.Write( 'service_updates', { self.GetServiceIdentifier() : [ HC.ServiceUpdate( HC.SERVICE_UPDATE_ERROR, HC.u( e ) ) ] } )
if isinstance( e, ( HydrusExceptions.PermissionException, HydrusExceptions.NetworkVersionException ) ):
HC.app.Write( 'service_updates', { self._service_identifier : [ HC.ServiceUpdate( HC.SERVICE_UPDATE_ACCOUNT, HC.GetUnknownAccount() ) ] } )
HC.app.Write( 'service_updates', { self.GetServiceIdentifier() : [ HC.ServiceUpdate( HC.SERVICE_UPDATE_ACCOUNT, HC.GetUnknownAccount() ) ] } )
raise
@ -2549,6 +2554,52 @@ class Service( HC.HydrusYAMLBase ):
if credentials.HasAccessKey(): self._info[ 'access_key' ] = credentials.GetAccessKey()
class ServiceManager( object ):
def __init__( self ):
self._lock = threading.Lock()
self.RefreshServices()
HC.pubsub.sub( self, 'RefreshServices', 'notify_new_services_data' )
def GetName( self, service_key ):
with self._lock:
service = self._keys_to_services[ service_key ]
return service.GetName()
def GetService( self, service_key ):
with self._lock: return self._keys_to_services[ service_key ]
def GetType( self, service_key ):
with self._lock:
service = self._keys_to_services[ service_key ]
return service.GetType()
def RefreshServices( self ):
with self._lock:
services = HC.app.Read( 'services' )
self._keys_to_services = { service.GetKey() : service for service in services }
class ThumbnailCache( object ):
def __init__( self ):

View File

@ -31,6 +31,8 @@ from twisted.internet import defer
ID_ANIMATED_EVENT_TIMER = wx.NewId()
ID_MAINTENANCE_EVENT_TIMER = wx.NewId()
MAINTENANCE_PERIOD = 12 * 60
class Controller( wx.App ):
def _Read( self, action, *args, **kwargs ): return self._db.Read( action, HC.HIGH_PRIORITY, *args, **kwargs )
@ -110,15 +112,7 @@ The database will be locked while the backup occurs, which may lock up your gui
def CurrentlyIdle( self ):
if HC.GetNow() - self._last_idle_time > 60 * 60: # a long time, so we probably just woke up from a sleep
self._last_idle_time = HC.GetNow()
return HC.GetNow() - self._last_idle_time > 20 * 60 # 20 mins since last user-initiated db request
def CurrentlyIdle( self ): return HC.GetNow() - self._timestamps[ 'last_user_db_use' ] > 30 * 60 # 30 mins since last user-initiated media_results query
def EventPubSub( self, event ):
@ -128,6 +122,8 @@ The database will be locked while the backup occurs, which may lock up your gui
finally: HC.currently_doing_pubsub = False
def GetDB( self ): return self._db
def GetFullscreenImageCache( self ): return self._fullscreen_image_cache
def GetGUI( self ): return self._gui
@ -140,6 +136,117 @@ The database will be locked while the backup occurs, which may lock up your gui
def GetThumbnailCache( self ): return self._thumbnail_cache
def InitCheckPassword( self ):
while True:
with wx.PasswordEntryDialog( None, 'Enter your password', 'Enter password' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
if hashlib.sha256( dlg.GetValue() ).digest() == HC.options[ 'password' ]: break
else: raise HydrusExceptions.PermissionException()
def InitDB( self ):
self._log = CC.Log()
try:
def make_temp_files_deletable( function_called, path, traceback_gumpf ):
os.chmod( path, stat.S_IWRITE )
function_called( path ) # try again
if os.path.exists( HC.TEMP_DIR ): shutil.rmtree( HC.TEMP_DIR, onerror = make_temp_files_deletable )
except: pass
try:
if not os.path.exists( HC.TEMP_DIR ): os.mkdir( HC.TEMP_DIR )
except: pass
db_initialised = False
while not db_initialised:
try:
self._db = ClientDB.DB()
db_initialised = True
except HydrusExceptions.DBAccessException as e:
try: print( HC.u( e ) )
except: print( repr( HC.u( e ) ) )
message = 'This instance of the client had a problem connecting to the database, which probably means an old instance is still closing.'
message += os.linesep + os.linesep
message += 'If the old instance does not close for a _very_ long time, you can usually safely force-close it from task manager.'
with ClientGUIDialogs.DialogYesNo( None, message, yes_label = 'wait a bit, then try again', no_label = 'forget it' ) as dlg:
if dlg.ShowModal() == wx.ID_YES: time.sleep( 3 )
else: raise HydrusExceptions.PermissionException()
threading.Thread( target = self._db.MainLoop, name = 'Database Main Loop' ).start()
def InitGUI( self ):
self._managers = {}
self._managers[ 'hydrus_sessions' ] = HydrusSessions.HydrusSessionManagerClient()
self._managers[ 'local_booru' ] = CC.LocalBooruCache()
self._managers[ 'services' ] = CC.ServiceManager()
self._managers[ 'tag_censorship' ] = HydrusTags.TagCensorshipManager()
self._managers[ 'tag_siblings' ] = HydrusTags.TagSiblingsManager()
self._managers[ 'tag_parents' ] = HydrusTags.TagParentsManager()
self._managers[ 'undo' ] = CC.UndoManager()
self._managers[ 'web_sessions' ] = HydrusSessions.WebSessionManagerClient()
self._fullscreen_image_cache = CC.RenderedImageCache( 'fullscreen' )
self._preview_image_cache = CC.RenderedImageCache( 'preview' )
self._thumbnail_cache = CC.ThumbnailCache()
CC.GlobalBMPs.STATICInitialise()
self._gui = ClientGUI.FrameGUI()
HC.pubsub.sub( self, 'Clipboard', 'clipboard' )
HC.pubsub.sub( self, 'RestartServer', 'restart_server' )
HC.pubsub.sub( self, 'RestartBooru', 'restart_booru' )
self.Bind( wx.EVT_TIMER, self.TIMEREventMaintenance, id = ID_MAINTENANCE_EVENT_TIMER )
self._maintenance_event_timer = wx.Timer( self, ID_MAINTENANCE_EVENT_TIMER )
self._maintenance_event_timer.Start( MAINTENANCE_PERIOD * 1000, wx.TIMER_CONTINUOUS )
# this is because of some bug in wx C++ that doesn't add these by default
wx.richtext.RichTextBuffer.AddHandler( wx.richtext.RichTextHTMLHandler() )
wx.richtext.RichTextBuffer.AddHandler( wx.richtext.RichTextXMLHandler() )
if HC.is_first_start: wx.CallAfter( self._gui.DoFirstStart )
if HC.is_db_updated: wx.CallLater( 1, HC.ShowText, 'The client has updated to version ' + HC.u( HC.SOFTWARE_VERSION ) + '!' )
self.RestartServer()
self.RestartBooru()
self._db.StartDaemons()
def MaintainDB( self ):
sys.stdout.flush()
@ -154,12 +261,18 @@ The database will be locked while the backup occurs, which may lock up your gui
if now - shutdown_timestamps[ CC.SHUTDOWN_TIMESTAMP_VACUUM ] > 86400 * 5: self.Write( 'vacuum' )
if now - shutdown_timestamps[ CC.SHUTDOWN_TIMESTAMP_DELETE_ORPHANS ] > 86400 * 3: self.Write( 'delete_orphans' )
if now - self._timestamps[ 'service_info_cache_fatten' ] > 60 * 20:
if now - self._timestamps[ 'last_service_info_cache_fatten' ] > 60 * 20:
HC.pubsub.pub( 'set_splash_text', 'fattening service info' )
service_identifiers = self.Read( 'service_identifiers' )
for service_identifier in service_identifiers: self.Read( 'service_info', service_identifier )
self._timestamps[ 'service_info_cache_fatten' ] = HC.GetNow()
HC.pubsub.pub( 'clear_closed_pages' )
def OnInit( self ):
@ -174,156 +287,25 @@ The database will be locked while the backup occurs, which may lock up your gui
self._local_service = None
self._booru_service = None
init_result = True
self.Bind( HC.EVT_PUBSUB, self.EventPubSub )
try:
try:
def make_temp_files_deletable( function_called, path, traceback_gumpf ):
os.chmod( path, stat.S_IWRITE )
function_called( path ) # try again
if os.path.exists( HC.TEMP_DIR ): shutil.rmtree( HC.TEMP_DIR, onerror = make_temp_files_deletable )
except: pass
splash = ClientGUI.FrameSplash( 'boot' )
try:
if not os.path.exists( HC.TEMP_DIR ): os.mkdir( HC.TEMP_DIR )
except: pass
return True
self._splash = ClientGUI.FrameSplash()
self.SetSplashText( 'log' )
self._log = CC.Log()
self.SetSplashText( 'db' )
db_initialised = False
while not db_initialised:
try:
self._db = ClientDB.DB()
db_initialised = True
except HydrusExceptions.DBAccessException as e:
try: print( HC.u( e ) )
except: print( repr( HC.u( e ) ) )
message = 'This instance of the client had a problem connecting to the database, which probably means an old instance is still closing.'
message += os.linesep + os.linesep
message += 'If the old instance does not close for a _very_ long time, you can usually safely force-close it from task manager.'
with ClientGUIDialogs.DialogYesNo( None, message, yes_label = 'wait a bit, then try again', no_label = 'forget it' ) as dlg:
if dlg.ShowModal() == wx.ID_YES: time.sleep( 3 )
else: raise HydrusExceptions.PermissionException()
threading.Thread( target = self._db.MainLoop, name = 'Database Main Loop' ).start()
if HC.options[ 'password' ] is not None:
self.SetSplashText( 'waiting for password' )
while True:
with wx.PasswordEntryDialog( None, 'Enter your password', 'Enter password' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
if hashlib.sha256( dlg.GetValue() ).digest() == HC.options[ 'password' ]: break
else: raise HydrusExceptions.PermissionException()
self.SetSplashText( 'caches and managers' )
self._managers = {}
self._managers[ 'hydrus_sessions' ] = HydrusSessions.HydrusSessionManagerClient()
self._managers[ 'tag_censorship' ] = HydrusTags.TagCensorshipManager()
self._managers[ 'tag_siblings' ] = HydrusTags.TagSiblingsManager()
self._managers[ 'tag_parents' ] = HydrusTags.TagParentsManager()
self._managers[ 'undo' ] = CC.UndoManager()
self._managers[ 'web_sessions' ] = HydrusSessions.WebSessionManagerClient()
self._managers[ 'local_booru' ] = CC.LocalBooruCache()
self._fullscreen_image_cache = CC.RenderedImageCache( 'fullscreen' )
self._preview_image_cache = CC.RenderedImageCache( 'preview' )
self._thumbnail_cache = CC.ThumbnailCache()
CC.GlobalBMPs.STATICInitialise()
self.SetSplashText( 'gui' )
self._gui = ClientGUI.FrameGUI()
HC.pubsub.sub( self, 'Clipboard', 'clipboard' )
HC.pubsub.sub( self, 'RestartServer', 'restart_server' )
HC.pubsub.sub( self, 'RestartBooru', 'restart_booru' )
self.Bind( HC.EVT_PUBSUB, self.EventPubSub )
# this is because of some bug in wx C++ that doesn't add these by default
wx.richtext.RichTextBuffer.AddHandler( wx.richtext.RichTextHTMLHandler() )
wx.richtext.RichTextBuffer.AddHandler( wx.richtext.RichTextXMLHandler() )
self.SetSplashText( 'starting daemons' )
if HC.is_first_start: self._gui.DoFirstStart()
if HC.is_db_updated: wx.CallLater( 1, HC.ShowText, 'The client has updated to version ' + HC.u( HC.SOFTWARE_VERSION ) + '!' )
self.RestartServer()
self.RestartBooru()
self._db.StartDaemons()
self._last_idle_time = 0.0
self.Bind( wx.EVT_TIMER, self.TIMEREventMaintenance, id = ID_MAINTENANCE_EVENT_TIMER )
self._maintenance_event_timer = wx.Timer( self, ID_MAINTENANCE_EVENT_TIMER )
self._maintenance_event_timer.Start( 20 * 60000, wx.TIMER_CONTINUOUS )
except sqlite3.OperationalError as e:
message = 'Database error!' + os.linesep + os.linesep + traceback.format_exc()
print message
wx.MessageBox( message )
init_result = False
except HydrusExceptions.PermissionException as e: init_result = False
except:
wx.MessageBox( 'Woah, bad error:' + os.linesep + os.linesep + traceback.format_exc() )
print( 'There was an error trying to start the splash screen!' )
init_result = False
print( traceback.format_exc() )
finally:
try: wx.CallAfter( self._splash.Destroy )
try: wx.CallAfter( splash.Destroy )
except: pass
return init_result
return False
def PrepStringForDisplay( self, text ):
@ -334,7 +316,7 @@ The database will be locked while the backup occurs, which may lock up your gui
def Read( self, action, *args, **kwargs ):
if action == 'media_results': self._last_idle_time = HC.GetNow()
if action == 'media_results': self._timestamps[ 'last_user_db_use' ] = HC.GetNow()
return self._Read( action, *args, **kwargs )
@ -503,7 +485,7 @@ Once it is done, the client will restart.'''
self._db.Shutdown()
while not self._db.GetLoopFinished(): time.sleep( 0.1 )
while not self._db.LoopIsFinished(): time.sleep( 0.1 )
self._db.RestoreBackup( path )
@ -518,12 +500,6 @@ Once it is done, the client will restart.'''
def SetSplashText( self, text ):
self._splash.SetText( text )
self.Yield() # this processes the event queue immediately, so the paint event can occur
def StartFileQuery( self, query_key, search_context ): HydrusThreading.CallToThread( self.THREADDoFileQuery, query_key, search_context )
def THREADDoFileQuery( self, query_key, search_context ):
@ -577,12 +553,15 @@ Once it is done, the client will restart.'''
def TIMEREventMaintenance( self, event ):
gc.collect()
last_time_this_ran = self._timestamps[ 'last_check_idle_time' ]
self._timestamps[ 'last_check_idle_time' ] = HC.GetNow()
# this tests if we probably just woke up from a sleep
if HC.GetNow() - last_time_this_ran > MAINTENANCE_PERIOD * 1.2: return
if self.CurrentlyIdle(): self.MaintainDB()
HC.pubsub.pub( 'clear_closed_pages' )
def WaitUntilGoodTimeToUseGUIThread( self ):
@ -596,8 +575,6 @@ Once it is done, the client will restart.'''
def Write( self, action, *args, **kwargs ):
self._last_idle_time = HC.GetNow()
if action == 'content_updates': self._managers[ 'undo' ].AddCommand( 'content_updates', *args, **kwargs )
return self._Write( action, HC.HIGH_PRIORITY, False, *args, **kwargs )

View File

@ -1505,6 +1505,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
def _DeleteOrphans( self, c ):
HC.pubsub.pub( 'set_splash_text', 'deleting orphan files' )
# careful of the .encode( 'hex' ) business here!
# files
@ -2670,9 +2672,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
( service_key, service_type, name, info ) = result
service_identifier = HC.ClientServiceIdentifier( service_key, service_type, name )
service = CC.Service( service_identifier, info )
service = CC.Service( service_key, service_type, name, info )
return service
@ -3856,6 +3856,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
self.pub_service_updates_after_commit( { service_identifier : [ HC.ServiceUpdate( HC.SERVICE_UPDATE_RESET ) ] } )
self.pub_after_commit( 'notify_new_pending' )
self.pub_after_commit( 'notify_new_services_data' )
self.pub_after_commit( 'notify_new_services_gui' )
self.pub_after_commit( 'permissions_are_stale' )
HC.ShowText( 'reset ' + service_name )
@ -4388,7 +4390,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
self.pub_after_commit( 'notify_new_pending' )
self.pub_after_commit( 'notify_new_services' )
self.pub_after_commit( 'notify_new_services_data' )
self.pub_after_commit( 'notify_new_services_gui' )
def _UpdateServices( self, c, edit_log ):
@ -4479,7 +4482,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
self.pub_after_commit( 'notify_new_pending' )
self.pub_after_commit( 'notify_new_services' )
self.pub_after_commit( 'notify_new_services_data' )
self.pub_after_commit( 'notify_new_services_gui' )
def _UpdateServiceInfo( self, c, service_id, update ):
@ -4521,7 +4525,7 @@ class DB( ServiceDB ):
while version < HC.SOFTWARE_VERSION:
HC.app.SetSplashText( 'updating db to v' + HC.u( version + 1 ) )
HC.pubsub.pub( 'set_splash_text', 'updating db to v' + HC.u( version + 1 ) )
time.sleep( 2 )
@ -4993,7 +4997,7 @@ class DB( ServiceDB ):
i += 1
if i % 100 == 0: HC.app.SetSplashText( 'reprocessing thumbs: ' + HC.ConvertIntToPrettyString( i ) )
if i % 100 == 0: HC.pubsub.pub( 'set_splash_text', 'reprocessing thumbs: ' + HC.ConvertIntToPrettyString( i ) )
except: print( 'When updating to v118, ' + path + '\'s phash could not be recalculated.' )
@ -5034,7 +5038,7 @@ class DB( ServiceDB ):
i += 1
if i % 100 == 0: HC.app.SetSplashText( 'creating video thumbs: ' + HC.ConvertIntToPrettyString( i ) )
if i % 100 == 0: HC.pubsub.pub( 'set_splash_text', 'creating video thumbs: ' + HC.ConvertIntToPrettyString( i ) )
except:
print( traceback.format_exc())
@ -5316,7 +5320,7 @@ class DB( ServiceDB ):
for i in range( 0, len( all_local_files ), 100 ):
HC.app.SetSplashText( 'updating db to v29 ' + HC.u( i ) + '/' + HC.u( len( all_local_files ) ) )
HC.pubsub.pub( 'set_splash_text', 'updating db to v29 ' + HC.u( i ) + '/' + HC.u( len( all_local_files ) ) )
local_files_subset = all_local_files[ i : i + 100 ]
@ -5366,7 +5370,7 @@ class DB( ServiceDB ):
for i in range( 0, len( all_thumbnails ), 500 ):
HC.app.SetSplashText( 'updating db to v30 ' + HC.u( i ) + '/' + HC.u( len( all_thumbnails ) ) )
HC.pubsub.pub( 'set_splash_text', 'updating db to v30 ' + HC.u( i ) + '/' + HC.u( len( all_thumbnails ) ) )
thumbnails_subset = all_thumbnails[ i : i + 500 ]
@ -5439,7 +5443,7 @@ class DB( ServiceDB ):
for i in range( 0, len( hashes ), 100 ):
HC.app.SetSplashText( 'updating db to v33 ' + HC.u( i ) + '/' + HC.u( len( hashes ) ) )
HC.pubsub.pub( 'set_splash_text', 'updating db to v33 ' + HC.u( i ) + '/' + HC.u( len( hashes ) ) )
hashes_subset = hashes[ i : i + 100 ]
@ -5477,7 +5481,7 @@ class DB( ServiceDB ):
# can't do it inside transaction
HC.app.SetSplashText( 'consolidating db - preparing' )
HC.pubsub.pub( 'set_splash_text', 'consolidating db - preparing' )
c.execute( 'ATTACH database "' + main_db_path + '" as main_db;' )
c.execute( 'ATTACH database "' + files_info_db_path + '" as files_info_db;' )
@ -5509,7 +5513,7 @@ class DB( ServiceDB ):
c.execute( 'DELETE FROM main.options;' )
HC.app.SetSplashText( 'consolidating db - 1/4' )
HC.pubsub.pub( 'set_splash_text', 'consolidating db - 1/4' )
c.execute( 'REPLACE INTO main.accounts SELECT * FROM main_db.accounts;' )
c.execute( 'REPLACE INTO main.addresses SELECT * FROM main_db.addresses;' )
@ -5528,18 +5532,18 @@ class DB( ServiceDB ):
c.execute( 'REPLACE INTO main.tags SELECT * FROM main_db.tags;' )
# don't do version, lol
HC.app.SetSplashText( 'consolidating db - 2/4' )
HC.pubsub.pub( 'set_splash_text', 'consolidating db - 2/4' )
c.execute( 'REPLACE INTO main.deleted_mappings SELECT * FROM mappings_db.deleted_mappings;' )
c.execute( 'REPLACE INTO main.mappings SELECT * FROM mappings_db.mappings;' )
c.execute( 'REPLACE INTO main.mapping_petitions SELECT * FROM mappings_db.mapping_petitions;' )
c.execute( 'REPLACE INTO main.pending_mappings SELECT * FROM mappings_db.pending_mappings;' )
HC.app.SetSplashText( 'consolidating db - 3/4' )
HC.pubsub.pub( 'set_splash_text', 'consolidating db - 3/4' )
c.execute( 'REPLACE INTO main.active_mappings SELECT * FROM active_mappings_db.active_mappings;' )
HC.app.SetSplashText( 'consolidating db - 4/4' )
HC.pubsub.pub( 'set_splash_text', 'consolidating db - 4/4' )
c.execute( 'REPLACE INTO main.deleted_files SELECT * FROM files_info_db.deleted_files;' )
c.execute( 'REPLACE INTO main.files_info SELECT * FROM files_info_db.files_info;' )
@ -5551,7 +5555,7 @@ class DB( ServiceDB ):
c.execute( 'COMMIT' )
HC.app.SetSplashText( 'consolidating db - cleaning up' )
HC.pubsub.pub( 'set_splash_text', 'consolidating db - cleaning up' )
c.execute( 'DETACH database main_db;' )
c.execute( 'DETACH database files_info_db;' )
@ -5959,7 +5963,7 @@ class DB( ServiceDB ):
c.execute( 'DELETE FROM active_pending_mappings WHERE tag_id = ?;', ( tag_id, ) )
HC.app.SetSplashText( 'making new cache, may take a minute' )
HC.pubsub.pub( 'set_splash_text', 'making new cache, may take a minute' )
c.execute( 'CREATE TABLE existing_tags ( namespace_id INTEGER, tag_id INTEGER, PRIMARY KEY( namespace_id, tag_id ) );' )
c.execute( 'CREATE INDEX existing_tags_tag_id_index ON existing_tags ( tag_id );' )
@ -6024,7 +6028,7 @@ class DB( ServiceDB ):
if version == 51:
HC.app.SetSplashText( 'making new indices' )
HC.pubsub.pub( 'set_splash_text', 'making new indices' )
c.execute( 'DROP INDEX mappings_namespace_id_index;' )
c.execute( 'DROP INDEX mappings_tag_id_index;' )
@ -6032,7 +6036,7 @@ class DB( ServiceDB ):
c.execute( 'CREATE INDEX mappings_service_id_tag_id_index ON mappings ( service_id, tag_id );' )
c.execute( 'CREATE INDEX mappings_service_id_hash_id_index ON mappings ( service_id, hash_id );' )
HC.app.SetSplashText( 'making some more new indices' )
HC.pubsub.pub( 'set_splash_text', 'making some more new indices' )
c.execute( 'DROP INDEX pending_mappings_namespace_id_index;' )
c.execute( 'DROP INDEX pending_mappings_tag_id_index;' )
@ -6187,7 +6191,7 @@ class DB( ServiceDB ):
if version == 64:
HC.app.SetSplashText( 'renaming db files' )
HC.pubsub.pub( 'set_splash_text', 'renaming db files' )
filenames = dircache.listdir( HC.CLIENT_FILES_DIR )
@ -6214,7 +6218,7 @@ class DB( ServiceDB ):
i += 1
if i % 250 == 0: HC.app.SetSplashText( 'renaming file ' + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( filenames ) ) )
if i % 250 == 0: HC.pubsub.pub( 'set_splash_text', 'renaming file ' + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( filenames ) ) )
c.execute( 'CREATE TABLE subscriptions ( subscriptions TEXT_YAML );' )
@ -6251,7 +6255,7 @@ class DB( ServiceDB ):
#
HC.app.SetSplashText( 'creating new db directories' )
HC.pubsub.pub( 'set_splash_text', 'creating new db directories' )
hex_chars = '0123456789abcdef'
@ -6266,7 +6270,7 @@ class DB( ServiceDB ):
if not os.path.exists( dir ): os.mkdir( dir )
HC.app.SetSplashText( 'generating file cache' )
HC.pubsub.pub( 'set_splash_text', 'generating file cache' )
filenames = dircache.listdir( HC.CLIENT_FILES_DIR )
@ -6288,10 +6292,10 @@ class DB( ServiceDB ):
i += 1
if i % 100 == 0: HC.app.SetSplashText( 'moving files - ' + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( filenames ) ) )
if i % 100 == 0: HC.pubsub.pub( 'set_splash_text', 'moving files - ' + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( filenames ) ) )
HC.app.SetSplashText( 'generating thumbnail cache' )
HC.pubsub.pub( 'set_splash_text', 'generating thumbnail cache' )
filenames = dircache.listdir( HC.CLIENT_THUMBNAILS_DIR )
@ -6313,7 +6317,7 @@ class DB( ServiceDB ):
i += 1
if i % 100 == 0: HC.app.SetSplashText( 'moving thumbnails - ' + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( filenames ) ) )
if i % 100 == 0: HC.pubsub.pub( 'set_splash_text', 'moving thumbnails - ' + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( filenames ) ) )
@ -6958,7 +6962,7 @@ class DB( ServiceDB ):
for ( i, service_id ) in enumerate( service_ids ):
HC.app.SetSplashText( 'copying mappings ' + str( i ) + '/' + str( len( service_ids ) ) )
HC.pubsub.pub( 'set_splash_text', 'copying mappings ' + str( i ) + '/' + str( len( service_ids ) ) )
c.execute( 'INSERT INTO processed_mappings SELECT * FROM mappings WHERE service_id = ?;', ( service_id, ) )
@ -6976,7 +6980,7 @@ class DB( ServiceDB ):
for ( i, filename ) in enumerate( current_updates ):
if i % 100 == 0: HC.app.SetSplashText( 'renaming updates ' + str( i ) + '/' + str( len( current_updates ) ) )
if i % 100 == 0: HC.pubsub.pub( 'set_splash_text', 'renaming updates ' + str( i ) + '/' + str( len( current_updates ) ) )
( service_key_hex, gumpf ) = filename.split( '_' )
@ -7024,6 +7028,8 @@ class DB( ServiceDB ):
def _Vacuum( self ):
HC.pubsub.pub( 'set_splash_text', 'vacuuming db' )
( db, c ) = self._GetDBCursor()
c.execute( 'VACUUM' )
@ -7035,8 +7041,6 @@ class DB( ServiceDB ):
HC.ShowText( 'vacuumed successfully' )
def GetLoopFinished( self ): return self._loop_finished
def pub_after_commit( self, topic, *args, **kwargs ): self._pubsubs.append( ( topic, args, kwargs ) )
def pub_content_updates_after_commit( self, service_identifiers_to_content_updates ):
@ -7051,6 +7055,8 @@ class DB( ServiceDB ):
self.pub_after_commit( 'service_updates_gui', service_identifiers_to_service_updates )
def LoopIsFinished( self ): return self._loop_finished
def MainLoop( self ):
def ProcessJob( c, job ):
@ -7304,7 +7310,7 @@ class DB( ServiceDB ):
HydrusThreading.DAEMONWorker( 'DownloadFiles', DAEMONDownloadFiles, ( 'notify_new_downloads', 'notify_new_permissions' ) )
HydrusThreading.DAEMONWorker( 'DownloadThumbnails', DAEMONDownloadThumbnails, ( 'notify_new_permissions', 'notify_new_thumbnails' ) )
HydrusThreading.DAEMONWorker( 'ResizeThumbnails', DAEMONResizeThumbnails, init_wait = 600 )
HydrusThreading.DAEMONWorker( 'SynchroniseAccounts', DAEMONSynchroniseAccounts, ( 'notify_new_services', 'permissions_are_stale' ) )
HydrusThreading.DAEMONWorker( 'SynchroniseAccounts', DAEMONSynchroniseAccounts, ( 'notify_new_services_gui', 'permissions_are_stale' ) )
HydrusThreading.DAEMONWorker( 'SynchroniseRepositories', DAEMONSynchroniseRepositories, ( 'notify_restart_repo_sync_daemon', 'notify_new_permissions' ) )
HydrusThreading.DAEMONWorker( 'SynchroniseSubscriptions', DAEMONSynchroniseSubscriptions, ( 'notify_restart_subs_sync_daemon', 'notify_new_subscriptions' ) )
HydrusThreading.DAEMONWorker( 'UPnP', DAEMONUPnP, ( 'notify_new_upnp_mappings', ), pre_callable_wait = 10 )

View File

@ -6,6 +6,7 @@ import ClientGUIDialogs
import ClientGUIDialogsManage
import ClientGUIPages
import HydrusDownloading
import HydrusExceptions
import HydrusFileHandling
import HydrusImageHandling
import HydrusNATPunch
@ -13,6 +14,7 @@ import HydrusThreading
import itertools
import os
import random
import sqlite3
import subprocess
import sys
import threading
@ -98,7 +100,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
HC.pubsub.sub( self, 'NotifyNewOptions', 'notify_new_options' )
HC.pubsub.sub( self, 'NotifyNewPending', 'notify_new_pending' )
HC.pubsub.sub( self, 'NotifyNewPermissions', 'notify_new_permissions' )
HC.pubsub.sub( self, 'NotifyNewServices', 'notify_new_services' )
HC.pubsub.sub( self, 'NotifyNewServices', 'notify_new_services_gui' )
HC.pubsub.sub( self, 'NotifyNewSessions', 'notify_new_sessions' )
HC.pubsub.sub( self, 'NotifyNewUndo', 'notify_new_undo' )
HC.pubsub.sub( self, 'RefreshStatusBar', 'refresh_status' )
@ -317,7 +319,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
def _AccountInfo( self, service_identifier ):
with wx.TextEntryDialog( self, 'Access key' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter the account\'s access key.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -603,7 +605,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
def _FetchIP( self, service_identifier ):
with wx.TextEntryDialog( self, 'File Hash' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter the file\'s hash.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -1227,7 +1229,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
service = HC.app.Read( 'service', service_identifier )
with wx.TextEntryDialog( self, 'Enter the access key for the account to be modified' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter the access key for the account to be modified.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -1387,7 +1389,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
def _PostNews( self, service_identifier ):
with wx.TextEntryDialog( self, 'Enter the news you would like to post.' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter the news you would like to post.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -1494,7 +1496,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
while True:
with wx.TextEntryDialog( self, 'enter a name for the new session', 'name session' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter a name for the new session.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -1544,7 +1546,7 @@ Do not ever forget your password! If you do, you'll have to manually insert a ya
The password is cleartext here but obscured in the entry dialog. Enter a blank password to remove.'''
with wx.TextEntryDialog( self, message, 'Enter new password' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, message, allow_blank = True ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -1580,7 +1582,7 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
def _StartURLDownload( self ):
with wx.TextEntryDialog( self, 'Enter URL' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter URL.' ) as dlg:
result = dlg.ShowModal()
@ -1601,7 +1603,7 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
def _StartYoutubeDownload( self ):
with wx.TextEntryDialog( self, 'Enter YouTube URL' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter YouTube URL.' ) as dlg:
result = dlg.ShowModal()
@ -1704,41 +1706,17 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
page = self._notebook.GetCurrentPage()
if page is not None:
try: splash = FrameSplash( 'exit' )
except:
( HC.options[ 'hpos' ], HC.options[ 'vpos' ] ) = page.GetSashPositions()
print( 'There was an error trying to start the splash screen!' )
HC.app.Write( 'save_options' )
self._SaveGUISession( 'last session' )
for page in [ self._notebook.GetPage( i ) for i in range( self._notebook.GetPageCount() ) ]:
print( traceback.format_exc() )
try: page.TestAbleToClose()
except Exception as e: return
try: wx.CallAfter( splash.Destroy )
except: pass
for page in [ self._notebook.GetPage( i ) for i in range( self._notebook.GetPageCount() ) ]:
try: page.CleanBeforeDestroy()
except: return
self._message_manager.CleanBeforeDestroy()
self._message_manager.Hide()
self.Hide()
# for some insane reason, the read makes the controller block until the writes are done!??!
# hence the hide, to make it appear the destroy is actually happening on time
HC.app.MaintainDB()
wx.CallAfter( self.Destroy )
def EventFocus( self, event ):
@ -2078,6 +2056,35 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
def Shutdown( self ):
self._message_manager.Hide()
self.Hide()
self._message_manager.CleanBeforeDestroy()
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()
HC.app.Write( 'save_options' )
self._SaveGUISession( 'last session' )
wx.CallAfter( self.Destroy )
def TestAbleToClose( self ):
for page in [ self._notebook.GetPage( i ) for i in range( self._notebook.GetPageCount() ) ]: page.TestAbleToClose()
class FrameComposeMessage( ClientGUICommon.Frame ):
def __init__( self, empty_draft_message ):
@ -2167,7 +2174,7 @@ class FrameReviewServices( ClientGUICommon.Frame ):
self.Show( True )
HC.pubsub.sub( self, 'RefreshServices', 'notify_new_services' )
HC.pubsub.sub( self, 'RefreshServices', 'notify_new_services_gui' )
wx.CallAfter( self.Raise )
@ -2877,40 +2884,182 @@ class FrameReviewServices( ClientGUICommon.Frame ):
class FrameSplash( ClientGUICommon.Frame ):
def __init__( self ):
def __init__( self, action ):
wx.Frame.__init__( self, None, style = wx.FRAME_NO_TASKBAR | wx.FRAME_SHAPED, title = 'hydrus client' )
wx.Frame.__init__( self, None, style = wx.FRAME_NO_TASKBAR, title = 'hydrus client' )
self._bmp = wx.EmptyBitmap( 154, 220, 32 ) # 32 bit for transparency?
self._bmp = wx.EmptyBitmap( 154, 220, 24 )
self.SetSize( ( 154, 220 ) )
self.Center()
self._last_drag_coordinates = None
self._total_drag_delta = ( 0, 0 )
self._initial_position = self.GetPosition()
# this is 124 x 166
self._hydrus = wx.Image( HC.STATIC_DIR + os.path.sep + 'hydrus_splash.png', type=wx.BITMAP_TYPE_PNG ).ConvertToBitmap()
dc = wx.BufferedDC( wx.ClientDC( self ), self._bmp )
dc.SetBackground( wx.Brush( wx.WHITE ) )
dc.Clear()
dc.DrawBitmap( self._hydrus, 15, 15 )
self.Bind( wx.EVT_PAINT, self.EventPaint )
self.Bind( wx.EVT_MOTION, self.EventDrag )
self.Bind( wx.EVT_LEFT_DOWN, self.EventDragBegin )
self.Bind( wx.EVT_LEFT_UP, self.EventDragEnd )
if action == 'boot':
self.SetText( 'initialising startup' )
my_thread = threading.Thread( target = self.BootApp, name = 'Application Boot Thread' )
elif action == 'exit':
self.SetText( 'initialising shutdown' )
my_thread = threading.Thread( target = self.ExitApp, name = 'Application Boot Thread' )
self.Show( True )
self.Bind( wx.EVT_MOUSE_EVENTS, self.OnMouseEvents )
HC.pubsub.sub( self, 'SetText', 'set_splash_text' )
wx.CallAfter( my_thread.start )
def BootApp( self ):
try:
wx.CallAfter( self.SetText, 'booting db' )
HC.app.InitDB()
if HC.options[ 'password' ] is not None:
wx.CallAfter( self.SetText, 'waiting for password' )
HC.app.InitCheckPassword()
wx.CallAfter( self.SetText, 'booting gui' )
wx.CallAfter( HC.app.InitGUI )
time.sleep( 1 )
except sqlite3.OperationalError as e:
text = 'Database error!' + os.linesep + os.linesep + traceback.format_exc()
print( text )
wx.CallAfter( wx.MessageBox, text )
except HydrusExceptions.PermissionException as e: pass
except:
text = 'Woah, bad error during startup!' + os.linesep * 2 + traceback.format_exc()
print( text )
wx.CallAfter( wx.MessageBox, text )
finally:
try: wx.CallAfter( self.Destroy )
except: pass
def EventDrag( self, event ):
if event.Dragging() and self._last_drag_coordinates is not None:
( old_x, old_y ) = self._last_drag_coordinates
( x, y ) = event.GetPosition()
( delta_x, delta_y ) = ( x - old_x, y - old_y )
( old_delta_x, old_delta_y ) = self._total_drag_delta
self._total_drag_delta = ( old_delta_x + delta_x, old_delta_y + delta_y )
( init_x, init_y ) = self._initial_position
( total_delta_x, total_delta_y ) = self._total_drag_delta
self.SetPosition( ( init_x + total_delta_x, init_y + total_delta_y ) )
def EventDragBegin( self, event ):
self._last_drag_coordinates = event.GetPosition()
event.Skip()
def EventDragEnd( self, event ):
self._last_drag_coordinates = None
event.Skip()
def EventPaint( self, event ): wx.BufferedPaintDC( self, self._bmp )
def OnMouseEvents( self, event ): pass
def ExitApp( self ):
try:
wx.CallAfter( self.SetText, 'exiting gui' )
gui = HC.app.GetGUI()
try: gui.TestAbleToClose()
except: return
gui.Shutdown()
wx.CallAfter( self.SetText, 'exiting db' )
db = HC.app.GetDB()
HC.app.MaintainDB()
db.Shutdown()
while not db.LoopIsFinished(): time.sleep( 0.1 )
except sqlite3.OperationalError as e:
text = 'Database error!' + os.linesep + os.linesep + traceback.format_exc()
print( text )
wx.CallAfter( wx.MessageBox, text )
except HydrusExceptions.PermissionException as e: pass
except:
text = 'Woah, bad error during shutdown!' + os.linesep * 2 + 'You may need to quit the program from task manager.' + os.linesep * 2 + traceback.format_exc()
print( text )
wx.CallAfter( wx.MessageBox, text )
finally:
try: wx.CallAfter( self.Destroy )
except: pass
def SetText( self, text ):
print( text )
dc = wx.BufferedDC( wx.ClientDC( self ), self._bmp )
dc.SetBackground( wx.Brush( wx.WHITE ) )
@ -2927,4 +3076,4 @@ class FrameSplash( ClientGUICommon.Frame ):
dc.DrawText( text, x, 200 )

View File

@ -1401,7 +1401,7 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ):
if interval is None:
with wx.TextEntryDialog( self, 'Enter the interval, in seconds', defaultValue='15' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter the interval, in seconds.', default = '15' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -1750,7 +1750,7 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
message = 'Enter a reason for this tag to be removed. A janitor will review your petition.'
with wx.TextEntryDialog( self, message ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, message ) as dlg:
if dlg.ShowModal() == wx.ID_OK:

View File

@ -292,9 +292,11 @@ class AutoCompleteDropdown( wx.TextCtrl ):
num_chars = len( self.GetValue() )
( char_limit, long_wait, short_wait ) = HC.options[ 'ac_timings' ]
if num_chars == 0: self._UpdateList()
elif num_chars < 3: self._lag_timer.Start( 500, wx.TIMER_ONE_SHOT )
else: self._lag_timer.Start( 250, wx.TIMER_ONE_SHOT )
elif num_chars < char_limit: self._lag_timer.Start( long_wait, wx.TIMER_ONE_SHOT )
else: self._lag_timer.Start( short_wait, wx.TIMER_ONE_SHOT )
def TIMEREventDropdownHide( self, event ):

View File

@ -2560,7 +2560,7 @@ class DialogInputLocalFiles( Dialog ):
while aes_key is None:
with wx.TextEntryDialog( HC.app.GetTopWindow(), 'Please enter the key for ' + path ) as dlg:
with ClientGUIDialogs.DialogTextEntry( HC.app.GetTopWindow(), 'Please enter the key for ' + path + '.' ) as dlg:
result = dlg.ShowModal()
@ -3589,7 +3589,7 @@ class DialogModifyAccounts( Dialog ):
def EventBan( self, event ):
with wx.TextEntryDialog( self, 'Enter reason for the ban' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter reason for the ban.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK: self._DoModification( HC.BAN, reason = dlg.GetValue() )
@ -3608,7 +3608,7 @@ class DialogModifyAccounts( Dialog ):
def EventSuperban( self, event ):
with wx.TextEntryDialog( self, 'Enter reason for the superban' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter reason for the superban.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK: self._DoModification( HC.SUPERBAN, reason = dlg.GetValue() )
@ -4602,11 +4602,12 @@ class DialogRegisterService( Dialog ):
return
service_identifier = HC.ClientServiceIdentifier( os.urandom( 32 ), self._service_type, 'temp registering service' )
service_key = os.urandom( 32 )
name = 'temp registering service'
info = { 'host' : host, 'port' : port }
service = CC.Service( service_identifier, info )
service = CC.Service( service_key, self._service_type, name, info )
response = service.Request( HC.GET, 'access_key', request_headers = { 'Hydrus-Key' : registration_key_encoded } )
@ -5148,7 +5149,7 @@ class DialogSetupCustomFilterActions( Dialog ):
existing_names = { self._favourites.GetString( i ) for i in range( self._favourites.GetCount() ) }
with wx.TextEntryDialog( self, 'Enter name for these favourite actions' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter name for these favourite actions.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -5506,6 +5507,90 @@ class DialogSetupExport( Dialog ):
self._tags_box.SetTagsByMedia( all_media )
class DialogTextEntry( Dialog ):
def __init__( self, parent, message, default = '', allow_blank = False ):
def InitialiseControls():
self._text = wx.TextCtrl( self, style = wx.TE_PROCESS_ENTER )
self._text.Bind( wx.EVT_CHAR, self.EventChar )
self._text.Bind( wx.EVT_TEXT_ENTER, self.EventEnter )
self._ok = wx.Button( self, id = wx.ID_OK, label = 'ok' )
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label = 'cancel' )
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
def PopulateControls():
self._text.SetValue( default )
self._CheckText()
def ArrangeControls():
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( self._ok, FLAGS_SMALL_INDENT )
hbox.AddF( self._cancel, FLAGS_SMALL_INDENT )
st_message = wx.StaticText( self, label = message )
st_message.Wrap( 480 )
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( st_message, FLAGS_BIG_INDENT )
vbox.AddF( self._text, FLAGS_EXPAND_BOTH_WAYS )
vbox.AddF( hbox, FLAGS_BUTTON_SIZERS )
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
x = max( x, 250 )
self.SetInitialSize( ( x, y ) )
Dialog.__init__( self, parent, 'enter text', position = 'center' )
self._allow_blank = allow_blank
InitialiseControls()
PopulateControls()
ArrangeControls()
def _CheckText( self ):
if not self._allow_blank:
if self._text.GetValue() == '': self._ok.Disable()
else: self._ok.Enable()
def EventChar( self, event ):
wx.CallAfter( self._CheckText )
event.Skip()
def EventEnter( self, event ):
if self._text.GetValue() != '': self.EndModal( wx.ID_OK )
def GetValue( self ): return self._text.GetValue()
class DialogYesNo( Dialog ):
def __init__( self, parent, message, yes_label = 'yes', no_label = 'no' ):

View File

@ -469,7 +469,7 @@ class DialogManageBoorus( ClientGUIDialogs.Dialog ):
def EventAdd( self, event ):
with wx.TextEntryDialog( self, 'Enter new booru\'s name' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter new booru\'s name.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -1009,7 +1009,7 @@ class DialogManageContacts( ClientGUIDialogs.Dialog ):
return
with wx.TextEntryDialog( self, 'Enter contact\'s address in the form contact_key@hostname:port' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter contact\'s address in the form contact_key@hostname:port.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -1062,7 +1062,7 @@ class DialogManageContacts( ClientGUIDialogs.Dialog ):
return
with wx.TextEntryDialog( self, 'Enter new contact\'s name' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter new contact\'s name.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -1833,7 +1833,7 @@ class DialogManageImageboards( ClientGUIDialogs.Dialog ):
def EventAdd( self, event ):
with wx.TextEntryDialog( self, 'Enter new site\'s name' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter new site\'s name.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -2039,7 +2039,7 @@ class DialogManageImageboards( ClientGUIDialogs.Dialog ):
def EventAdd( self, event ):
with wx.TextEntryDialog( self, 'Enter new imageboard\'s name' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter new imageboard\'s name.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -2814,6 +2814,15 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
self._num_autocomplete_chars = wx.SpinCtrl( self._file_page, min = 1, max = 100 )
self._num_autocomplete_chars.SetToolTipString( 'how many characters you enter before the gui fetches autocomplete results from the db' + os.linesep + 'increase this if you find autocomplete results are slow' )
self._autocomplete_long_wait = wx.SpinCtrl( self._file_page, min = 0, max = 10000 )
self._autocomplete_long_wait.SetToolTipString( 'how long the gui will wait, after you enter a character, before it queries the db with what you have entered so far' )
self._autocomplete_short_wait_chars = wx.SpinCtrl( self._file_page, min = 1, max = 100 )
self._autocomplete_short_wait_chars.SetToolTipString( 'how many characters you enter before the gui starts waiting the short time before querying the db' )
self._autocomplete_short_wait = wx.SpinCtrl( self._file_page, min = 0, max = 10000 )
self._autocomplete_short_wait.SetToolTipString( 'how long the gui will wait, after you enter a lot of characters, before it queries the db with what you have entered so far' )
self._listbook.AddPage( self._file_page, 'files and memory' )
# gui
@ -3007,6 +3016,14 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
self._num_autocomplete_chars.SetValue( HC.options[ 'num_autocomplete_chars' ] )
( char_limit, long_wait, short_wait ) = HC.options[ 'ac_timings' ]
self._autocomplete_long_wait.SetValue( long_wait )
self._autocomplete_short_wait_chars.SetValue( char_limit )
self._autocomplete_short_wait.SetValue( short_wait )
#
gui_sessions = HC.app.Read( 'gui_sessions' )
@ -3183,6 +3200,15 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
gridbox.AddF( wx.StaticText( self._file_page, label = 'Autocomplete character threshold: ' ), FLAGS_MIXED )
gridbox.AddF( self._num_autocomplete_chars, FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._file_page, label = 'Autocomplete long wait (ms): ' ), FLAGS_MIXED )
gridbox.AddF( self._autocomplete_long_wait, FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._file_page, label = 'Autocomplete short wait threshold: ' ), FLAGS_MIXED )
gridbox.AddF( self._autocomplete_short_wait_chars, FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._file_page, label = 'Autocomplete short wait (ms): ' ), FLAGS_MIXED )
gridbox.AddF( self._autocomplete_short_wait, FLAGS_MIXED )
self._file_page.SetSizer( gridbox )
#
@ -3574,6 +3600,14 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
HC.options[ 'num_autocomplete_chars' ] = self._num_autocomplete_chars.GetValue()
long_wait = self._autocomplete_long_wait.GetValue()
char_limit = self._autocomplete_short_wait_chars.GetValue()
short_wait = self._autocomplete_short_wait.GetValue()
HC.options[ 'ac_timings' ] = ( char_limit, long_wait, short_wait )
HC.options[ 'namespace_colours' ] = self._namespace_colours.GetNamespaceColours()
sort_by_choices = []
@ -4668,7 +4702,7 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
def EventAdd( self, event ):
with wx.TextEntryDialog( self, 'Enter new service\'s name' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter new service\'s name.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -5143,10 +5177,12 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
def EventCheckService( self, event ):
( service_identifier, info ) = self.GetInfo()
service_type = service_identifier.GetType()
service = CC.Service( service_identifier, info )
service_key = service_identifier.GetServiceKey()
service_type = service_identifier.GetType()
name = service_identifier.GetName()
service = CC.Service( service_key, service_type, name, info )
try: root = service.Request( HC.GET, '' )
except HydrusExceptions.WrongServiceTypeException:
@ -5423,7 +5459,7 @@ class DialogManageSubscriptions( ClientGUIDialogs.Dialog ):
def EventAdd( self, event ):
with wx.TextEntryDialog( self, 'Enter name for subscription' ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter name for subscription.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
@ -6317,7 +6353,7 @@ class DialogManageTagParents( ClientGUIDialogs.Dialog ):
message = 'Enter a reason for this pair to be removed. A janitor will review your petition.'
with wx.TextEntryDialog( self, message ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, message ) as dlg:
if dlg.ShowModal() == wx.ID_OK: reason = dlg.GetValue()
else: return
@ -6373,7 +6409,7 @@ class DialogManageTagParents( ClientGUIDialogs.Dialog ):
message = 'Enter a reason for ' + pair_string + ' to be added. A janitor will review your petition.'
with wx.TextEntryDialog( self, message ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, message ) as dlg:
if dlg.ShowModal() == wx.ID_OK: reason = dlg.GetValue()
else: return
@ -6787,7 +6823,7 @@ class DialogManageTagSiblings( ClientGUIDialogs.Dialog ):
message = 'Enter a reason for this pair to be removed. A janitor will review your petition.'
with wx.TextEntryDialog( self, message ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, message ) as dlg:
if dlg.ShowModal() == wx.ID_OK: reason = dlg.GetValue()
else: return
@ -6843,7 +6879,7 @@ class DialogManageTagSiblings( ClientGUIDialogs.Dialog ):
message = 'Enter a reason for ' + pair_string + ' to be added. A janitor will review your petition.'
with wx.TextEntryDialog( self, message ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, message ) as dlg:
if dlg.ShowModal() == wx.ID_OK: reason = dlg.GetValue()
else: return
@ -7489,7 +7525,7 @@ class DialogManageTags( ClientGUIDialogs.Dialog ):
message = 'Enter a reason for this tag to be removed. A janitor will review your petition.'
with wx.TextEntryDialog( self, message ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, message ) as dlg:
if dlg.ShowModal() == wx.ID_OK: reason = dlg.GetValue()
else: return

View File

@ -477,7 +477,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
if len( hashes ) == 1: message = 'Enter a reason for this file to be removed from ' + file_service_identifier.GetName() + '.'
else: message = 'Enter a reason for these ' + HC.ConvertIntToPrettyString( len( hashes ) ) + ' files to be removed from ' + file_service_identifier.GetName() + '.'
with wx.TextEntryDialog( self, message ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, message ) as dlg:
if dlg.ShowModal() == wx.ID_OK:

View File

@ -982,7 +982,7 @@ class DraftBodyPanel( wx.Panel ):
if text_attribute.HasURL(): initial_url = text_attribute.GetURL()
else: initial_url = 'http://'
with wx.TextEntryDialog( self, 'Enter url', defaultValue = initial_url ) as dlg:
with ClientGUIDialogs.DialogTextEntry( self, 'Enter url.', default = initial_url ) as dlg:
if dlg.ShowModal() == wx.ID_OK:

View File

@ -64,7 +64,7 @@ options = {}
# Misc
NETWORK_VERSION = 13
SOFTWARE_VERSION = 124
SOFTWARE_VERSION = 125
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )

View File

@ -38,16 +38,16 @@ def ConvertToPngIfBmp( path ):
os.remove( temp_path )
def EfficientlyResizeCVImage( cv_image, ( target_x, target_y ) ):
def EfficientlyResizeNumpyImage( numpy_image, ( target_x, target_y ) ):
( im_y, im_x, depth ) = cv_image.shape
( im_y, im_x, depth ) = numpy_image.shape
if target_x >= im_x and target_y >= im_y: return cv_image
if target_x >= im_x and target_y >= im_y: return numpy_image
result = cv_image
result = numpy_image
# this seems to slow things down a lot, at least for cv!
#if im_x > 2 * target_x and im_y > 2 * target_y: result = cv2.resize( cv_image, ( 2 * target_x, 2 * target_y ), interpolation = cv2.INTER_NEAREST )
#if im_x > 2 * target_x and im_y > 2 * target_y: result = cv2.resize( numpy_image, ( 2 * target_x, 2 * target_y ), interpolation = cv2.INTER_NEAREST )
return cv2.resize( result, ( target_x, target_y ), interpolation = cv2.INTER_LINEAR )
@ -64,15 +64,15 @@ def EfficientlyResizePILImage( pil_image, ( target_x, target_y ) ):
return pil_image.resize( ( target_x, target_y ), PILImage.ANTIALIAS )
def EfficientlyThumbnailCVImage( cv_image, ( target_x, target_y ) ):
def EfficientlyThumbnailNumpyImage( numpy_image, ( target_x, target_y ) ):
( im_y, im_x, depth ) = cv_image.shape
( im_y, im_x, depth ) = numpy_image.shape
if target_x >= im_x and target_y >= im_y: return cv_image
if target_x >= im_x and target_y >= im_y: return numpy_image
( target_x, target_y ) = GetThumbnailResolution( ( im_x, im_y ), ( target_x, target_y ) )
return cv2.resize( cv_image, ( target_x, target_y ), interpolation = cv2.INTER_AREA )
return cv2.resize( numpy_image, ( target_x, target_y ), interpolation = cv2.INTER_AREA )
def EfficientlyThumbnailPILImage( pil_image, ( target_x, target_y ) ):
@ -85,24 +85,24 @@ def EfficientlyThumbnailPILImage( pil_image, ( target_x, target_y ) ):
pil_image.thumbnail( ( target_x, target_y ), PILImage.ANTIALIAS )
def GenerateCVImage( path ):
def GenerateNumpyImage( path ):
cv_image = cv2.imread( self._path, flags = -1 ) # flags = -1 loads alpha channel, if present
numpy_image = cv2.imread( self._path, flags = -1 ) # flags = -1 loads alpha channel, if present
( y, x, depth ) = cv_image.shape
( y, x, depth ) = numpy_image.shape
if depth == 4: raise Exception( 'CV is bad at alpha!' )
else: cv_image = cv2.cvtColor( cv_image, cv2.COLOR_BGR2RGB )
else: numpy_image = cv2.cvtColor( numpy_image, cv2.COLOR_BGR2RGB )
return cv_image
return numpy_image
def GenerateHydrusBitmap( path ):
try:
cv_image = GenerateCVImage( path )
numpy_image = GenerateNumpyImage( path )
return GenerateHydrusBitmapFromNumPyImage( cv_image )
return GenerateHydrusBitmapFromNumPyImage( numpy_image )
except:
@ -111,12 +111,12 @@ def GenerateHydrusBitmap( path ):
return GenerateHydrusBitmapFromPILImage( pil_image )
def GenerateHydrusBitmapFromNumPyImage( cv_image ):
def GenerateHydrusBitmapFromNumPyImage( numpy_image ):
( y, x, depth ) = cv_image.shape
( y, x, depth ) = numpy_image.shape
if depth == 4: return HydrusBitmap( cv_image.data, wx.BitmapBufferFormat_RGBA, ( x, y ) )
else: return HydrusBitmap( cv_image.data, wx.BitmapBufferFormat_RGB, ( x, y ) )
if depth == 4: return HydrusBitmap( numpy_image.data, wx.BitmapBufferFormat_RGBA, ( x, y ) )
else: return HydrusBitmap( numpy_image.data, wx.BitmapBufferFormat_RGB, ( x, y ) )
def GenerateNumPyImageFromPILImage( pil_image ):
@ -154,9 +154,9 @@ def GenerateHydrusBitmapFromPILImage( pil_image ):
def GeneratePerceptualHash( path ):
cv_image = cv2.imread( path, cv2.CV_LOAD_IMAGE_UNCHANGED )
numpy_image = cv2.imread( path, cv2.CV_LOAD_IMAGE_UNCHANGED )
( y, x, depth ) = cv_image.shape
( y, x, depth ) = numpy_image.shape
if depth == 4:
@ -164,15 +164,15 @@ def GeneratePerceptualHash( path ):
white = numpy.ones( ( x, y ) ) * 255
# create weight and transform cv_image to greyscale
# create weight and transform numpy_image to greyscale
cv_alpha = cv_image[ :, :, 3 ]
numpy_alpha = numpy_image[ :, :, 3 ]
cv_image_bgr = cv_image[ :, :, :3 ]
numpy_image_bgr = numpy_image[ :, :, :3 ]
cv_image_gray = cv2.cvtColor( cv_image_bgr, cv2.COLOR_BGR2GRAY )
numpy_image_gray = cv2.cvtColor( numpy_image_bgr, cv2.COLOR_BGR2GRAY )
cv_image_result = numpy.empty( ( y, x ), numpy.float32 )
numpy_image_result = numpy.empty( ( y, x ), numpy.float32 )
# paste greyscale onto the white
@ -182,33 +182,33 @@ def GeneratePerceptualHash( path ):
for j in range( x ):
opacity = float( cv_alpha[ i, j ] ) / 255.0
opacity = float( numpy_alpha[ i, j ] ) / 255.0
grey_part = cv_image_gray[ i, j ] * opacity
grey_part = numpy_image_gray[ i, j ] * opacity
white_part = 255 * ( 1 - opacity )
pixel = grey_part + white_part
cv_image_result[ i, j ] = pixel
numpy_image_result[ i, j ] = pixel
cv_image_gray = cv_image_result
numpy_image_gray = numpy_image_result
# use 255 for white weight, alpha for image weight
else:
cv_image_gray = cv2.cvtColor( cv_image, cv2.COLOR_BGR2GRAY )
numpy_image_gray = cv2.cvtColor( numpy_image, cv2.COLOR_BGR2GRAY )
cv_image_tiny = cv2.resize( cv_image_gray, ( 32, 32 ), interpolation = cv2.INTER_AREA )
numpy_image_tiny = cv2.resize( numpy_image_gray, ( 32, 32 ), interpolation = cv2.INTER_AREA )
# convert to float and calc dct
cv_image_tiny_float = numpy.float32( cv_image_tiny )
numpy_image_tiny_float = numpy.float32( numpy_image_tiny )
dct = cv2.dct( cv_image_tiny_float )
dct = cv2.dct( numpy_image_tiny_float )
# take top left 8x8 of dct
@ -282,19 +282,19 @@ def old_GeneratePerceptualHash( path ):
# convert to mat
cv_thumbnail_8 = cv.CreateMatHeader( 32, 32, cv.CV_8UC1 )
numpy_thumbnail_8 = cv.CreateMatHeader( 32, 32, cv.CV_8UC1 )
cv.SetData( cv_thumbnail_8, thumbnail.tostring() )
cv.SetData( numpy_thumbnail_8, thumbnail.tostring() )
cv_thumbnail_32 = cv.CreateMat( 32, 32, cv.CV_32FC1 )
numpy_thumbnail_32 = cv.CreateMat( 32, 32, cv.CV_32FC1 )
cv.Convert( cv_thumbnail_8, cv_thumbnail_32 )
cv.Convert( numpy_thumbnail_8, numpy_thumbnail_32 )
# compute dct
dct = cv.CreateMat( 32, 32, cv.CV_32FC1 )
cv.DCT( cv_thumbnail_32, dct, cv.CV_DXT_FORWARD )
cv.DCT( numpy_thumbnail_32, dct, cv.CV_DXT_FORWARD )
# take top left 8x8 of dct
@ -594,11 +594,11 @@ class ImageContainer( RasterContainer ):
try:
cv_image = GenerateCVImage( self._path )
numpy_image = GenerateNumpyImage( self._path )
resized_cv_image = EfficientlyResizeCVImage( cv_image, self._target_resolution )
resized_numpy_image = EfficientlyResizeNumpyImage( numpy_image, self._target_resolution )
return GenerateHydrusBitmapFromNumPyImage( resized_cv_image )
return GenerateHydrusBitmapFromNumPyImage( resized_numpy_image )
except:

View File

@ -106,13 +106,9 @@ class HydrusPubSub( object ):
with self._lock:
# this stops the pubsubs started at the beginning of the program screwing with the queue
if HC.app.IsMainLoopRunning():
self._pubsubs.append( ( topic, args, kwargs ) )
wx.PostEvent( HC.app, PubSubEvent() )
self._pubsubs.append( ( topic, args, kwargs ) )
wx.PostEvent( HC.app, PubSubEvent() )

View File

@ -141,25 +141,10 @@ class HydrusSessionManagerServer( object ):
def __init__( self ):
existing_sessions = HC.app.Read( 'sessions' )
self._account_ids_to_session_keys = collections.defaultdict( HC.default_dict_set )
self._account_ids_to_accounts = collections.defaultdict( dict )
self._sessions = collections.defaultdict( dict )
for ( session_key, service_identifier, account, expiry ) in existing_sessions:
self._sessions[ service_identifier ][ session_key ] = ( account, expiry )
account_id = account.GetAccountId()
self._account_ids_to_session_keys[ service_identifier ][ account_id ].add( session_key )
self._lock = threading.Lock()
self.RefreshAllAccounts()
HC.pubsub.sub( self, 'RefreshAllAccounts', 'update_all_session_accounts' )
@ -245,21 +230,26 @@ class HydrusSessionManagerServer( object ):
def RefreshAllAccounts( self ):
existing_sessions = HC.app.Read( 'sessions' )
self._account_ids_to_session_keys = collections.defaultdict( HC.default_dict_set )
self._account_ids_to_accounts = collections.defaultdict( dict )
self._sessions = collections.defaultdict( dict )
for ( session_key, service_identifier, account, expiry ) in existing_sessions:
with self._lock:
self._sessions[ service_identifier ][ session_key ] = ( account, expiry )
existing_sessions = HC.app.Read( 'sessions' )
account_id = account.GetAccountId()
self._account_ids_to_session_keys = collections.defaultdict( HC.default_dict_set )
self._account_ids_to_session_keys[ service_identifier ][ account_id ].add( session_key )
self._account_ids_to_accounts = collections.defaultdict( dict )
self._sessions = collections.defaultdict( dict )
for ( session_key, service_identifier, account, expiry ) in existing_sessions:
self._sessions[ service_identifier ][ session_key ] = ( account, expiry )
account_id = account.GetAccountId()
self._account_ids_to_session_keys[ service_identifier ][ account_id ].add( session_key )
self._account_ids_to_accounts[ service_identifier ][ account_id ] = account

View File

@ -96,7 +96,7 @@ class DAEMONWorker( DAEMON ):
try: self._callable()
except Exception as e:
HC.ShowText( 'Daemon ' + name + ' encountered an exception:' )
HC.ShowText( 'Daemon ' + self._name + ' encountered an exception:' )
HC.ShowException( e )

View File

@ -654,7 +654,7 @@ class GIFRenderer( object ):
if self._cv_mode:
( retval, cv_image ) = self._cv_video.read()
( retval, numpy_image ) = self._cv_video.read()
if not retval:
@ -676,7 +676,7 @@ class GIFRenderer( object ):
else: self._pil_canvas = self._pil_image
cv_image = HydrusImageHandling.GenerateNumPyImageFromPILImage( self._pil_canvas )
numpy_image = HydrusImageHandling.GenerateNumPyImageFromPILImage( self._pil_canvas )
self._next_render_index = ( self._next_render_index + 1 ) % self._num_frames
@ -700,7 +700,7 @@ class GIFRenderer( object ):
return cv_image
return numpy_image
def _InitialiseCV( self ):
@ -739,13 +739,13 @@ class GIFRenderer( object ):
try:
cv_image = self._GetCurrentFrame()
numpy_image = self._GetCurrentFrame()
cv_image = HydrusImageHandling.EfficientlyResizeCVImage( cv_image, self._target_resolution )
numpy_image = HydrusImageHandling.EfficientlyResizeNumpyImage( numpy_image, self._target_resolution )
cv_image = cv2.cvtColor( cv_image, cv2.COLOR_BGR2RGB )
numpy_image = cv2.cvtColor( numpy_image, cv2.COLOR_BGR2RGB )
self._last_frame = cv_image
self._last_frame = numpy_image
except HydrusExceptions.CantRenderWithCVException:
@ -757,19 +757,19 @@ class GIFRenderer( object ):
return self._RenderCurrentFrame()
else: cv_image = self._last_frame
else: numpy_image = self._last_frame
else:
cv_image = self._GetCurrentFrame()
numpy_image = self._GetCurrentFrame()
cv_image = HydrusImageHandling.EfficientlyResizeCVImage( cv_image, self._target_resolution )
numpy_image = HydrusImageHandling.EfficientlyResizeNumpyImage( numpy_image, self._target_resolution )
self._last_frame = cv_image
self._last_frame = numpy_image
return cv_image
return numpy_image
def _RewindGIF( self ):

View File

@ -47,12 +47,12 @@ class Controller( wx.App ):
try:
self.Bind( HC.EVT_PUBSUB, self.EventPubSub )
self._db = ServerDB.DB()
self.Bind( wx.EVT_MENU, self.EventExit, id=wx.ID_EXIT )
self.Bind( HC.EVT_PUBSUB, self.EventPubSub )
self._managers = {}
self._managers[ 'restricted_services_sessions' ] = HydrusSessions.HydrusSessionManagerServer()

View File

@ -51,7 +51,7 @@ class TestClientDB( unittest.TestCase ):
self._db.Shutdown()
while not self._db.GetLoopFinished(): time.sleep( 0.1 )
while not self._db.LoopIsFinished(): time.sleep( 0.1 )
def make_temp_files_deletable( function_called, path, traceback_gumpf ):

View File

@ -128,15 +128,13 @@ class TestServer( unittest.TestCase ):
def _test_file_repo( self, host, port ):
service_identifier = HC.ClientServiceIdentifier( os.urandom( 32 ), HC.FILE_REPOSITORY, 'service' )
info = {}
info[ 'host' ] = host
info[ 'port' ] = port
info[ 'access_key' ] = self._access_key
service = CC.Service( service_identifier, info )
service = CC.Service( os.urandom( 32 ), HC.FILE_REPOSITORY, 'service', info )
# file
@ -292,15 +290,13 @@ class TestServer( unittest.TestCase ):
def _test_repo( self, host, port, service_type ):
service_identifier = HC.ClientServiceIdentifier( os.urandom( 32 ), service_type, 'service' )
info = {}
info[ 'host' ] = host
info[ 'port' ] = port
info[ 'access_key' ] = self._access_key
service = CC.Service( service_identifier, info )
service = CC.Service( os.urandom( 32 ), service_type, 'service', info )
# news
@ -366,14 +362,14 @@ class TestServer( unittest.TestCase ):
def _test_restricted( self, host, port, service_type ):
service_identifier = HC.ClientServiceIdentifier( os.urandom( 32 ), service_type, 'service' )
service_key = os.urandom( 32 )
info = {}
info[ 'host' ] = host
info[ 'port' ] = port
service = CC.Service( service_identifier, info )
service = CC.Service( service_key, service_type, 'service', info )
# access_key
@ -391,7 +387,7 @@ class TestServer( unittest.TestCase ):
info[ 'access_key' ] = self._access_key
service = CC.Service( service_identifier, info )
service = CC.Service( service_key, service_type, 'service', info )
# set up session
@ -399,7 +395,7 @@ class TestServer( unittest.TestCase ):
account = self._account
service_for_session_manager = CC.Service( service_identifier, info )
service_for_session_manager = CC.Service( service_key, service_type, 'service', info )
HC.app.SetRead( 'service', service_for_session_manager )
@ -482,14 +478,14 @@ class TestServer( unittest.TestCase ):
def _test_server_admin( self, host, port ):
service_identifier = HC.ClientServiceIdentifier( os.urandom( 32 ), HC.SERVER_ADMIN, 'service' )
service_key = os.urandom( 32 )
info = {}
info[ 'host' ] = host
info[ 'port' ] = port
service = CC.Service( service_identifier, info )
service = CC.Service( service_key, HC.SERVER_ADMIN, 'service', info )
# init
@ -505,7 +501,7 @@ class TestServer( unittest.TestCase ):
info[ 'access_key' ] = self._access_key
service = CC.Service( service_identifier, info )
service = CC.Service( service_key, HC.SERVER_ADMIN, 'service', info )
# backup

View File

@ -78,7 +78,11 @@ class App( wx.App ):
info[ 'max_monthly_data' ] = None
info[ 'used_monthly_data' ] = 0
service = CC.Service( HC.LOCAL_BOORU_SERVICE_IDENTIFIER, info )
service_key = HC.LOCAL_BOORU_SERVICE_IDENTIFIER.GetServiceKey()
service_type = HC.LOCAL_BOORU_SERVICE_IDENTIFIER.GetType()
name = HC.LOCAL_BOORU_SERVICE_IDENTIFIER.GetName()
service = CC.Service( service_key, service_type, name, info )
HC.app.SetRead( 'service', service )