Version 138

This commit is contained in:
Hydrus 2014-12-03 16:56:40 -06:00
parent ddcf0181fd
commit 71b68f1f2c
18 changed files with 756 additions and 266 deletions

View File

@ -8,6 +8,25 @@
<div class="content">
<h3>changelog</h3>
<ul>
<li><h3>version 138</h3></li>
<ul>
<li>created new 'maintenance and memory' options page in the manage options dialog, and moved some things over from 'files and memory', which is now 'files and thumbnails'</li>
<li>added options for idle, vacuum, and delete orphans periods to the 'maintenance and memory' page in the manage options dialog</li>
<li>fixed the incredibly annoying animated scanbar delayed-frame bug, where a click on the scanbar would not draw the new frame until the old frame's expected delay was complete. scanbar scanning is a lot smoother all around, now</li>
<li>animations now show their current frame number in the animation scanbar</li>
<li>status bar now shows inbox/archived counts on any selection</li>
<li>reworked static image zoom code so they resize beautifully, without jaggies, at the cost of a bit of CPU and memory</li>
<li>created new flexible message pathway</li>
<li>moved most messages to new pathway</li>
<li>improved a bunch of message and job_key related code</li>
<li>btw: messages will no longer close themselves; their end state is now to report what happened until you dismiss them. if this turns out to be annoying, I'll change it</li>
<li>fixed the pending menu not updating its count when files imported and added tags via archive sync</li>
<li>improved the logic behind the 'computer just woke from sleep' calculation</li>
<li>improved the accuracy of the 'client is currently idle' calculation</li>
<li>improved database vacuum so the .db-wal file is flushed afterwards, for both client and server</li>
<li>because of better vacuuming, server db backup no longer needs to create a bloated .db-wal backup</li>
<li>removed a very common superfluous empty tag upload packet in normal tag uploads</li>
</ul>
<li><h3>version 137</h3></li>
<ul>
<li>eliminated a loophole in the tag-pending process that allowed zero-length subtags through during archive sync</li>

View File

@ -71,7 +71,7 @@
<p>All of a server's files and options are stored in its accompanying .db file and respective subdirectories, which are created on first startup (just like with the client). You can backup and restore these files just by copying them about, but you have to be careful how you do it with a server; when it is running, it has a live connection to its database, and all sorts of things could be written or read at any time. If you just try to copy the .db somewhere and someone uploads a file, something might break. Instead, you have two options:</p>
<ul>
<li>Shut down the server, copy the .db files, then restart it. This is the only way, currently, to restore a db.</li>
<li>Hit admin->your server->make a backup. This will lock the db server-side while it makes a copy right in the /db directory. The .db file will be tidied up and copied to .db.backup and the subdirectories will be copied to _backup as well. When the operation is complete, you can ftp/batch-copy/whatever these backup files wherever you like.</li>
<li>Hit admin->your server->make a backup on your client. This will lock the db server-side while it makes a copy right in the /db directory. The .db file will be tidied up and copied to .db.backup and the subdirectories will be copied to _backup as well. When the operation is complete, you can ftp/batch-copy/whatever these backup files wherever you like.</li>
</ul>
<h3>OMG EVERYTHING WENT WRONG</h3>
<p>If you get to a point where you can no longer boot the repository, try running SQLite Studio and opening server.db. If the issue is simple—like manually changing the port number—you may be in luck. Send me an email if it is tricky.</p>

View File

@ -193,6 +193,9 @@ CLIENT_DEFAULT_OPTIONS[ 'gui_capitalisation' ] = False
CLIENT_DEFAULT_OPTIONS[ 'default_gui_session' ] = 'just a blank page'
CLIENT_DEFAULT_OPTIONS[ 'ac_timings' ] = ( 3, 500, 250 )
CLIENT_DEFAULT_OPTIONS[ 'thread_checker_timings' ] = ( 3, 1200 )
CLIENT_DEFAULT_OPTIONS[ 'idle_period' ] = 60 * 30
CLIENT_DEFAULT_OPTIONS[ 'maintenance_delete_orphans_period' ] = 86400 * 3
CLIENT_DEFAULT_OPTIONS[ 'maintenance_vacuum_period' ] = 86400 * 5
system_predicates = {}
@ -328,7 +331,9 @@ def CatchExceptionClient( etype, value, tb ):
info[ 'caller_traceback' ] = caller_traceback
info[ 'db_traceback' ] = db_traceback
message = HC.Message( HC.MESSAGE_TYPE_DB_ERROR, info )
job_key = HC.JobKey( pausable = False, cancellable = False )
message = HC.Message( HC.MESSAGE_TYPE_DB_ERROR, job_key, info )
else:
@ -336,7 +341,9 @@ def CatchExceptionClient( etype, value, tb ):
trace = ''.join( trace_list )
message = HC.Message( HC.MESSAGE_TYPE_ERROR, { 'error' : ( etype, value, trace ) } )
job_key = HC.JobKey( pausable = False, cancellable = False )
message = HC.Message( HC.MESSAGE_TYPE_ERROR, job_key, { 'error' : ( etype, value, trace ) } )
HC.pubsub.pub( 'message', message )
@ -789,7 +796,9 @@ def ShowExceptionClient( e ):
info[ 'caller_traceback' ] = caller_traceback
info[ 'db_traceback' ] = db_traceback
message = HC.Message( HC.MESSAGE_TYPE_DB_ERROR, info )
job_key = HC.JobKey( pausable = False, cancellable = False )
message = HC.Message( HC.MESSAGE_TYPE_DB_ERROR, job_key, info )
else:
@ -804,13 +813,21 @@ def ShowExceptionClient( e ):
else: trace = ''.join( traceback.format_exception( etype, value, tb ) )
message = HC.Message( HC.MESSAGE_TYPE_ERROR, { 'error' : ( etype, value, trace ) } )
job_key = HC.JobKey( pausable = False, cancellable = False )
message = HC.Message( HC.MESSAGE_TYPE_ERROR, job_key, { 'error' : ( etype, value, trace ) } )
HC.pubsub.pub( 'message', message )
def ShowTextClient( text ): HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_TEXT, { 'text' : text } ) )
def ShowTextClient( text ):
job_key = HC.JobKey( pausable = False, cancellable = False )
job_key.SetVariable( 'popup_message_text_1', text )
HC.pubsub.pub( 'message', job_key )
class AutocompleteMatches( object ):
def __init__( self, matches ):

View File

@ -35,6 +35,15 @@ MAINTENANCE_PERIOD = 5 * 60
class Controller( wx.App ):
def _CheckIfJustWokeFromSleep( self ):
last_maintenance_time = self._timestamps[ 'last_maintenance_time' ]
# this tests if we probably just woke up from a sleep
if HC.GetNow() - last_maintenance_time > MAINTENANCE_PERIOD + ( 5 * 60 ): self._just_woke_from_sleep = True
else: self._just_woke_from_sleep = False
def _Read( self, action, *args, **kwargs ): return self._db.Read( action, HC.HIGH_PRIORITY, *args, **kwargs )
def _Write( self, action, priority, synchronous, *args, **kwargs ): return self._db.Write( action, priority, synchronous, *args, **kwargs )
@ -155,7 +164,12 @@ class Controller( wx.App ):
def CurrentlyIdle( self ): return HC.GetNow() - self._timestamps[ 'last_user_action' ] > 30 * 60 # 30 mins since last canvas media swap
def CurrentlyIdle( self ):
if HC.options[ 'idle_period' ] == 0: return False
return HC.GetNow() - self._timestamps[ 'last_user_action' ] > HC.options[ 'idle_period' ]
def EventPubSub( self, event ):
@ -292,7 +306,12 @@ class Controller( wx.App ):
self._db.StartDaemons()
def JustWokeFromSleep( self ): return self._just_woke_from_sleep
def JustWokeFromSleep( self ):
if not self._just_woke_from_sleep: self._CheckIfJustWokeFromSleep()
return self._just_woke_from_sleep
def MaintainDB( self ):
@ -302,8 +321,15 @@ class Controller( wx.App ):
shutdown_timestamps = self.Read( 'shutdown_timestamps' )
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 HC.options[ 'maintenance_vacuum_period' ] != 0:
if now - shutdown_timestamps[ CC.SHUTDOWN_TIMESTAMP_VACUUM ] > HC.options[ 'maintenance_vacuum_period' ]: self.Write( 'vacuum' )
if HC.options[ 'maintenance_delete_orphans_period' ] != 0:
if now - shutdown_timestamps[ CC.SHUTDOWN_TIMESTAMP_DELETE_ORPHANS ] > HC.options[ 'maintenance_delete_orphans_period' ]: self.Write( 'delete_orphans' )
if now - self._timestamps[ 'last_service_info_cache_fatten' ] > 60 * 20:
@ -592,13 +618,9 @@ class Controller( wx.App ):
sys.stdout.flush()
sys.stderr.flush()
last_time_this_ran = self._timestamps[ 'last_check_idle_time' ]
self._CheckIfJustWokeFromSleep()
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 + ( 5 * 60 ): self._just_woke_from_sleep = True
else: self._just_woke_from_sleep = False
self._timestamps[ 'last_maintenance_time' ] = HC.GetNow()
if not self._just_woke_from_sleep and self.CurrentlyIdle(): self.MaintainDB()

View File

@ -1456,9 +1456,9 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
job_key = HC.JobKey( pausable = False, cancellable = False )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, prefix_string + 'preparing', job_key )
job_key.SetVariable( 'popup_message_text_1', prefix_string + 'preparing' )
HC.pubsub.pub( 'message', message )
HC.pubsub.pub( 'message', job_key )
info = self._c.execute( 'SELECT hash_id, mime FROM files_info WHERE service_id = ?;', ( self._local_file_service_id, ) ).fetchall()
@ -1468,10 +1468,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
if i % 100 == 0:
message.SetInfo( 'range', len( info ) )
message.SetInfo( 'value', i )
message.SetInfo( 'text', prefix_string + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( info ) ) )
message.SetInfo( 'mode', 'gauge' )
job_key.SetVariable( 'popup_message_text_1', prefix_string + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( info ) ) )
job_key.SetVariable( 'popup_message_gauge_1', ( i, len( info ) ) )
hash = self._GetHash( hash_id )
@ -1492,12 +1490,17 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
message.SetInfo( 'text', prefix_string + 'deleting the incorrect records' )
message.SetInfo( 'mode', 'text' )
job_key.DeleteVariable( 'popup_message_gauge_1' )
job_key.SetVariable( 'popup_message_text_1', prefix_string + 'deleting the incorrect records' )
self._DeleteFiles( self._local_file_service_id, deletee_hash_ids )
message.SetInfo( 'text', prefix_string + 'done! ' + HC.ConvertIntToPrettyString( len( deletee_hash_ids ) ) + ' files deleted!' )
text = prefix_string + 'done! '
if len( deletee_hash_ids ) == 0: text += 'all files ok!'
else: text += HC.ConvertIntToPrettyString( len( deletee_hash_ids ) ) + ' files deleted!'
job_key.SetVariable( 'popup_message_text_1', text )
def _DeleteFiles( self, service_id, hash_ids ):
@ -1643,7 +1646,12 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
self.pub_service_updates_after_commit( { service_key : [ HC.ServiceUpdate( HC.SERVICE_UPDATE_DELETE_PENDING ) ] } )
def _DeleteServiceInfo( self ): self._c.execute( 'DELETE FROM service_info;' )
def _DeleteServiceInfo( self ):
self._c.execute( 'DELETE FROM service_info;' )
self.pub_after_commit( 'notify_new_pending' )
def _DeleteYAMLDump( self, dump_type, dump_name = None ):
@ -1675,9 +1683,9 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
job_key = HC.JobKey( pausable = False, cancellable = False )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, prefix_string + 'preparing', job_key )
job_key.SetVariable( 'popup_message_text_1', prefix_string + 'preparing' )
HC.pubsub.pub( 'message', message )
HC.pubsub.pub( 'message', job_key )
service_id = self._GetServiceId( service_key )
@ -1698,10 +1706,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
if i % 1000 == 0:
message.SetInfo( 'range', len( hash_ids ) )
message.SetInfo( 'value', i )
message.SetInfo( 'text', prefix_string + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( hash_ids ) ) )
message.SetInfo( 'mode', 'gauge' )
job_key.SetVariable( 'popup_message_text_1', prefix_string + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( hash_ids ) ) )
job_key.SetVariable( 'popup_message_gauge_1', ( i, len( hash_ids ) ) )
if hash_type == HydrusTagArchive.HASH_TYPE_SHA256: archive_hash = self._GetHash( hash_id )
@ -1723,12 +1729,12 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
hta.AddMappings( archive_hash, tags )
message.SetInfo( 'text', prefix_string + 'commiting the change and vacuuming the archive' )
message.SetInfo( 'mode', 'text' )
job_key.DeleteVariable( 'popup_message_gauge_1' )
job_key.SetVariable( 'popup_message_text_1', prefix_string + 'committing the change and vacuuming the archive' )
hta.CommitBigJob()
message.SetInfo( 'text', prefix_string + 'done!' )
job_key.SetVariable( 'popup_message_text_1', prefix_string + 'done!' )
def _FattenAutocompleteCache( self ):
@ -1928,6 +1934,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
def _GetFileQueryIds( self, search_context ):
HC.app.ResetIdleTimer()
system_predicates = search_context.GetSystemPredicates()
file_service_key = search_context.GetFileServiceKey()
@ -2714,21 +2722,21 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
pending = [ ( ( self._GetNamespaceTag( old_namespace_id, old_tag_id ), self._GetNamespaceTag( new_namespace_id, new_tag_id ) ), self._GetReason( reason_id ) ) for ( old_namespace_id, old_tag_id, new_namespace_id, new_tag_id, reason_id ) in self._c.execute( 'SELECT old_namespace_id, old_tag_id, new_namespace_id, new_tag_id, reason_id FROM tag_sibling_petitions WHERE service_id = ? AND status = ?;', ( service_id, HC.PENDING ) ).fetchall() ]
content_data[ HC.CONTENT_DATA_TYPE_TAG_SIBLINGS ][ HC.CONTENT_UPDATE_PENDING ] = pending
if len( pending ) > 0: content_data[ HC.CONTENT_DATA_TYPE_TAG_SIBLINGS ][ HC.CONTENT_UPDATE_PENDING ] = pending
petitioned = [ ( ( self._GetNamespaceTag( old_namespace_id, old_tag_id ), self._GetNamespaceTag( new_namespace_id, new_tag_id ) ), self._GetReason( reason_id ) ) for ( old_namespace_id, old_tag_id, new_namespace_id, new_tag_id, reason_id ) in self._c.execute( 'SELECT old_namespace_id, old_tag_id, new_namespace_id, new_tag_id, reason_id FROM tag_sibling_petitions WHERE service_id = ? AND status = ?;', ( service_id, HC.PETITIONED ) ).fetchall() ]
content_data[ HC.CONTENT_DATA_TYPE_TAG_SIBLINGS ][ HC.CONTENT_UPDATE_PETITION ] = petitioned
if len( petitioned ) > 0: content_data[ HC.CONTENT_DATA_TYPE_TAG_SIBLINGS ][ HC.CONTENT_UPDATE_PETITION ] = petitioned
# tag parents
pending = [ ( ( self._GetNamespaceTag( child_namespace_id, child_tag_id ), self._GetNamespaceTag( parent_namespace_id, parent_tag_id ) ), self._GetReason( reason_id ) ) for ( child_namespace_id, child_tag_id, parent_namespace_id, parent_tag_id, reason_id ) in self._c.execute( 'SELECT child_namespace_id, child_tag_id, parent_namespace_id, parent_tag_id, reason_id FROM tag_parent_petitions WHERE service_id = ? AND status = ?;', ( service_id, HC.PENDING ) ).fetchall() ]
content_data[ HC.CONTENT_DATA_TYPE_TAG_PARENTS ][ HC.CONTENT_UPDATE_PENDING ] = pending
if len( pending ) > 0: content_data[ HC.CONTENT_DATA_TYPE_TAG_PARENTS ][ HC.CONTENT_UPDATE_PENDING ] = pending
petitioned = [ ( ( self._GetNamespaceTag( child_namespace_id, child_tag_id ), self._GetNamespaceTag( parent_namespace_id, parent_tag_id ) ), self._GetReason( reason_id ) ) for ( child_namespace_id, child_tag_id, parent_namespace_id, parent_tag_id, reason_id ) in self._c.execute( 'SELECT child_namespace_id, child_tag_id, parent_namespace_id, parent_tag_id, reason_id FROM tag_parent_petitions WHERE service_id = ? AND status = ?;', ( service_id, HC.PETITIONED ) ).fetchall() ]
content_data[ HC.CONTENT_DATA_TYPE_TAG_PARENTS ][ HC.CONTENT_UPDATE_PETITION ] = petitioned
if len( petitioned ) > 0: content_data[ HC.CONTENT_DATA_TYPE_TAG_PARENTS ][ HC.CONTENT_UPDATE_PETITION ] = petitioned
if len( content_data ) > 0:
@ -3865,7 +3873,11 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
text = name + ' at ' + time.ctime( timestamp ) + ':' + os.linesep * 2 + post
self.pub_after_commit( 'message', HC.Message( HC.MESSAGE_TYPE_TEXT, { 'text' : text } ) )
job_key = HC.JobKey( pausable = False, cancellable = False )
job_key.SetVariable( 'popup_message_text_1', text )
self.pub_after_commit( 'message', job_key )
@ -4023,7 +4035,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
def _SyncFileToTagArchive( self, hash_id, archive_name, namespaces, service_key ):
def _SyncFileToTagArchive( self, hash_id, archive_name, namespaces, service_key, pub_immediate = False ):
hta = self._tag_archives[ archive_name ]
@ -4056,7 +4068,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
service_keys_to_content_updates = { service_key : content_updates }
self._ProcessContentUpdates( service_keys_to_content_updates, pub_immediate = True )
self._ProcessContentUpdates( service_keys_to_content_updates, pub_immediate = pub_immediate )
@ -4066,28 +4078,26 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
job_key = HC.JobKey( pausable = False, cancellable = False )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, prefix_string + 'preparing', job_key )
job_key.SetVariable( 'popup_message_text_1', prefix_string + 'preparing' )
HC.pubsub.pub( 'message', message )
HC.pubsub.pub( 'message', job_key )
hash_ids = [ hash_id for ( hash_id, ) in self._c.execute( 'SELECT hash_id FROM files_info WHERE service_id = ?;', ( self._local_file_service_id, ) ) ]
for ( i, hash_id ) in enumerate( hash_ids ):
try: self._SyncFileToTagArchive( hash_id, archive_name, namespaces, service_key )
try: self._SyncFileToTagArchive( hash_id, archive_name, namespaces, service_key, pub_immediate = True )
except: pass
if i % 100 == 0:
message.SetInfo( 'range', len( hash_ids ) )
message.SetInfo( 'value', i )
message.SetInfo( 'text', prefix_string + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( hash_ids ) ) )
message.SetInfo( 'mode', 'gauge' )
job_key.SetVariable( 'popup_message_text_1', prefix_string + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( hash_ids ) ) )
job_key.SetVariable( 'popup_message_gauge_1', ( i, len( hash_ids ) ) )
message.SetInfo( 'text', prefix_string + 'done!' )
message.SetInfo( 'mode', 'text' )
job_key.DeleteVariable( 'popup_message_gauge_1' )
job_key.SetVariable( 'popup_message_text_1', prefix_string + 'done!' )
self.pub_after_commit( 'notify_new_pending' )
@ -4520,9 +4530,11 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
if message is None:
message = HC.Message( HC.MESSAGE_TYPE_TEXT, { 'text' : 'updating services: deleting tag data' } )
job_key = HC.JobKey( pausable = False, cancellable = False )
job_key.SetVariable( 'popup_message_text_1', 'updating services: deleting tag data' )
HC.pubsub.pub( 'message', message )
HC.pubsub.pub( 'message', job_key )
@ -4603,11 +4615,11 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
if recalc_combined_mappings:
message.SetInfo( 'text', 'updating services: recalculating combined tag data' )
job_key.SetVariable( 'popup_message_text_1', 'updating services: recalculating combined tag data' )
self._RecalcCombinedMappings()
message.SetInfo( 'text', 'updating services: done!' )
job_key.SetVariable( 'popup_message_text_1', 'updating services: done!' )
self.pub_after_commit( 'notify_new_pending' )
@ -5027,9 +5039,11 @@ class DB( ServiceDB ):
prefix = 'deleting old resized thumbnails: '
message = HC.Message( HC.MESSAGE_TYPE_TEXT, { 'text' : prefix + 'initialising' } )
job_key = HC.JobKey( pausable = False, cancellable = False )
HC.pubsub.pub( 'message', message )
job_key.SetVariable( 'popup_message_text_1', prefix + 'initialising' )
HC.pubsub.pub( 'message', job_key )
thumbnail_paths = ( path for path in CC.IterateAllThumbnailPaths() if path.endswith( '_resized' ) )
@ -5037,12 +5051,12 @@ class DB( ServiceDB ):
os.remove( path )
if i % 100 == 0: message.SetInfo( 'text', prefix + 'done ' + HC.ConvertIntToPrettyString( i ) )
if i % 100 == 0: job_key.SetVariable( 'popup_message_text_1', prefix + 'done ' + HC.ConvertIntToPrettyString( i ) )
self.pub_after_commit( 'thumbnail_resize' )
message.SetInfo( 'text', prefix + 'done!' )
job_key.SetVariable( 'popup_message_text_1', prefix + 'done!' )
self.pub_after_commit( 'notify_new_options' )
@ -5773,6 +5787,11 @@ class DB( ServiceDB ):
self._c.execute( 'REPLACE INTO shutdown_timestamps ( shutdown_type, timestamp ) VALUES ( ?, ? );', ( CC.SHUTDOWN_TIMESTAMP_VACUUM, HC.GetNow() ) )
self._c.close()
self._db.close()
self._InitDBCursor()
HC.ShowText( 'Database maintenance: vacuumed successfully.' )
@ -6262,7 +6281,12 @@ def DAEMONCheckImportFolders():
text = HC.u( len( successful_hashes ) ) + ' files imported from ' + folder_path
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_FILES, { 'text' : text, 'hashes' : successful_hashes } ) )
job_key = HC.JobKey( pausable = False, cancellable = False )
job_key.SetVariable( 'popup_message_text_1', text )
job_key.SetVariable( 'popup_message_files', successful_hashes )
HC.pubsub.pub( 'message', job_key )
details[ 'last_checked' ] = now
@ -6975,11 +6999,11 @@ def DAEMONSynchroniseSubscriptions():
try:
job_key = HC.JobKey( pausable = True, cancellable = False )
job_key = HC.JobKey( pausable = True, cancellable = True )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, 'checking ' + name + ' subscription', job_key )
job_key.SetVariable( 'popup_message_text_1', 'checking ' + name + ' subscription' )
HC.pubsub.pub( 'message', message )
HC.pubsub.pub( 'message', job_key )
do_tags = len( advanced_tag_options ) > 0
@ -7045,28 +7069,38 @@ def DAEMONSynchroniseSubscriptions():
while job_key.IsPaused():
message.SetInfo( 'text', 'paused' )
job_key.SetVariable( 'popup_message_text_1', 'paused' )
time.sleep( 1 )
if HC.shutdown: return
if message.IsClosed(): return
if job_key.IsCancelled():
job_key.SetVariable( 'popup_message_text_1', name + ' check was cancelled' )
return
while HC.options[ 'pause_subs_sync' ]:
message.SetInfo( 'text', 'subscriptions paused' )
job_key.SetVariable( 'popup_message_text_1', 'subscriptions paused' )
time.sleep( 5 )
if HC.shutdown: return
if message.IsClosed(): return
if job_key.IsCancelled():
job_key.SetVariable( 'popup_message_text_1', name + ' check was cancelled' )
return
if HC.subs_changed:
message.Close()
job_key.SetVariable( 'popup_message_text_1', 'subscriptions were changed during processing; this job was abandoned' )
HC.pubsub.pub( 'notify_restart_subs_sync_daemon' )
@ -7092,7 +7126,7 @@ def DAEMONSynchroniseSubscriptions():
all_url_args.extend( fresh_url_args )
message.SetInfo( 'text', 'found ' + HC.ConvertIntToPrettyString( len( all_url_args ) ) + ' new files for ' + name )
job_key.SetVariable( 'popup_message_text_1', 'found ' + HC.ConvertIntToPrettyString( len( all_url_args ) ) + ' new files for ' + name )
@ -7101,32 +7135,28 @@ def DAEMONSynchroniseSubscriptions():
if len( downloaders ) == 0: break
message.SetInfo( 'range', len( all_url_args ) )
message.SetInfo( 'value', 0 )
message.SetInfo( 'mode', 'gauge' )
all_url_args.reverse() # to do oldest first, which means we can save incrementally
i = 1
num_new = 0
successful_hashes = set()
for url_args in all_url_args:
for ( i, url_args ) in enumerate( all_url_args ):
while HC.options[ 'pause_subs_sync' ]:
message.SetInfo( 'text', 'subscriptions paused' )
job_key.SetVariable( 'popup_message_text_1', 'subscriptions paused' )
time.sleep( 5 )
if HC.shutdown: return
if job_key.IsCancelled(): return
if HC.subs_changed:
message.Close()
job_key.SetVariable( 'popup_message_text_1', 'subscriptions were changed during processing; this job was abandoned' )
HC.pubsub.pub( 'notify_restart_subs_sync_daemon' )
return
@ -7143,8 +7173,8 @@ def DAEMONSynchroniseSubscriptions():
x_out_of_y = HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( all_url_args ) )
message.SetInfo( 'value', i )
message.SetInfo( 'text', name + ': ' + x_out_of_y + ' : checking url status' )
job_key.SetVariable( 'popup_message_text_1', name + ': ' + x_out_of_y + ' : checking url status' )
job_key.SetVariable( 'popup_message_gauge_1', ( i, len( all_url_args ) ) )
( status, hash ) = HC.app.ReadDaemon( 'url_status', url )
@ -7156,7 +7186,7 @@ def DAEMONSynchroniseSubscriptions():
try:
message.SetInfo( 'text', name + ': ' + x_out_of_y + ' : found file in db, fetching tags' )
job_key.SetVariable( 'popup_message_text_1', name + ': ' + x_out_of_y + ' : found file in db, fetching tags' )
tags = downloader.GetTags( *url_args )
@ -7173,7 +7203,7 @@ def DAEMONSynchroniseSubscriptions():
num_new += 1
message.SetInfo( 'text', name + ': ' + x_out_of_y + ' : downloading file' )
job_key.SetVariable( 'popup_message_text_1', name + ': ' + x_out_of_y + ' : downloading file' )
if do_tags: ( temp_path, tags ) = downloader.GetFileAndTags( *url_args )
else:
@ -7185,7 +7215,7 @@ def DAEMONSynchroniseSubscriptions():
service_keys_to_tags = HydrusDownloading.ConvertTagsToServiceKeysToTags( tags, advanced_tag_options )
message.SetInfo( 'text', name + ': ' + x_out_of_y + ' : importing file' )
job_key.SetVariable( 'popup_message_text_1', name + ': ' + x_out_of_y + ' : importing file' )
( status, hash ) = HC.app.WriteSynchronous( 'import_file', temp_path, advanced_import_options = advanced_import_options, service_keys_to_tags = service_keys_to_tags, url = url )
@ -7202,8 +7232,6 @@ def DAEMONSynchroniseSubscriptions():
HC.ShowException( e )
i += 1
if i % 20 == 0:
info[ 'site_type' ] = site_type
@ -7223,24 +7251,25 @@ def DAEMONSynchroniseSubscriptions():
HC.app.WaitUntilGoodTimeToUseGUIThread()
job_key.DeleteVariable( 'popup_message_gauge_1' )
if len( successful_hashes ) > 0:
text = HC.u( len( successful_hashes ) ) + ' files imported from ' + name
job_key.SetVariable( 'popup_message_text_1', HC.u( len( successful_hashes ) ) + ' files imported from ' + name )
job_key.SetVariable( 'popup_message_files', successful_hashes )
message.SetInfo( 'text', text )
message.SetInfo( 'hashes', successful_hashes )
message.SetInfo( 'mode', 'files' )
else:
job_key.SetPausable( False )
job_key.SetVariable( 'popup_message_text_1', name + 'subscription checked, but no new files' )
else: message.Close()
job_key.SetPausable( False )
job_key.SetCancellable( False )
last_checked = now
except Exception as e:
if 'message' in locals(): message.Close()
last_checked = now + HC.UPDATE_DURATION
HC.ShowText( 'Problem with ' + name + ':' )

View File

@ -146,9 +146,9 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
job_key = HC.JobKey( pausable = False, cancellable = False )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, 'gathering pending and petitioned', job_key )
job_key.SetVariable( 'popup_message_text_1', 'gathering pending and petitioned' )
HC.pubsub.pub( 'message', message )
HC.pubsub.pub( 'message', job_key )
result = HC.app.Read( 'pending', service_key )
@ -163,30 +163,17 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
media_results = HC.app.Read( 'media_results', HC.LOCAL_FILE_SERVICE_KEY, upload_hashes )
num_uploads = len( media_results )
num_other_messages = 1
if not update.IsEmpty(): num_other_messages += 1
gauge_range = num_uploads + num_other_messages
i = 1
message.SetInfo( 'range', gauge_range )
message.SetInfo( 'value', i )
message.SetInfo( 'text', 'connecting to repository' )
message.SetInfo( 'mode', 'cancelable gauge' )
job_key.SetVariable( 'popup_message_text_1', 'connecting to repository' )
good_hashes = []
error_messages = set()
for media_result in media_results:
for ( i, media_result ) in enumerate( media_results ):
if job_key.IsCancelled():
message.Close()
job_key.SetVariable( 'popup_message_text_1', 'upload cancelled' )
return
@ -196,8 +183,8 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
hash = media_result.GetHash()
mime = media_result.GetMime()
message.SetInfo( 'value', i )
message.SetInfo( 'text', 'Uploading file ' + HC.ConvertIntToPrettyString( i ) + ' of ' + HC.ConvertIntToPrettyString( num_uploads ) )
job_key.SetVariable( 'popup_message_text_1', 'Uploading file ' + HC.ConvertIntToPrettyString( i + 1 ) + ' of ' + HC.ConvertIntToPrettyString( len( media_results ) ) )
job_key.SetVariable( 'popup_message_gauge_1', ( i, len( media_results ) ) )
try:
@ -233,8 +220,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
i += 1
message.SetInfo( 'value', i )
message.SetInfo( 'text', 'uploading petitions' )
job_key.SetVariable( 'popup_message_text_1', 'uploading petitions' )
service.Request( HC.POST, 'update', { 'update' : update } )
@ -247,32 +233,19 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
updates = result
num_updates = len( updates )
job_key.SetVariable( 'popup_message_text_1', 'connecting to repository' )
num_other_messages = 1
gauge_range = num_updates + num_other_messages + 1
i = 1
message.SetInfo( 'range', gauge_range )
message.SetInfo( 'value', i )
message.SetInfo( 'text', 'connecting to repository' )
message.SetInfo( 'mode', 'cancelable gauge' )
for update in updates:
for ( i, update ) in enumerate( updates ):
if job_key.IsCancelled():
message.Close()
job_key.SetVariable( 'popup_message_text_1', 'upload cancelled' )
return
i += 1
message.SetInfo( 'value', i )
message.SetInfo( 'text', 'posting update' )
job_key.SetVariable( 'popup_message_text_1', 'posting update: ' + HC.ConvertIntToPrettyString( i + 1 ) + '/' + HC.ConvertIntToPrettyString( len( updates ) ) )
job_key.SetVariable( 'popup_message_gauge_1', ( i, len( updates ) ) )
service.Request( HC.POST, 'update', { 'update' : update } )
@ -285,11 +258,12 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
HC.app.WaitUntilGoodTimeToUseGUIThread()
except Exception as e: HC.ShowException( e )
message.SetInfo( 'text', 'upload done' )
message.SetInfo( 'mode', 'text' )
job_key.DeleteVariable( 'popup_message_gauge_1' )
job_key.SetVariable( 'popup_message_text_1', 'upload done!' )
HC.pubsub.pub( 'notify_new_pending' )
@ -1474,9 +1448,11 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
prefix = 'regenerating thumbnails: '
message = HC.Message( HC.MESSAGE_TYPE_TEXT, { 'text' : prefix + 'creating directories' } )
job_key = HC.JobKey( pausable = False, cancellable = False )
HC.pubsub.pub( 'message', message )
job_key.SetVariable( 'popup_message_text_1', prefix + 'creating directories' )
HC.pubsub.pub( 'message', job_key )
if not os.path.exists( HC.CLIENT_THUMBNAILS_DIR ): os.mkdir( HC.CLIENT_THUMBNAILS_DIR )
@ -1499,7 +1475,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
if mime in HC.MIMES_WITH_THUMBNAILS:
if i % 100 == 0: message.SetInfo( 'text', prefix + HC.ConvertIntToPrettyString( i ) + ' done' )
if i % 100 == 0: job_key.SetVariable( 'popup_message_text_1', prefix + HC.ConvertIntToPrettyString( i ) + ' done' )
( base, filename ) = os.path.split( path )
@ -1531,8 +1507,8 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
if num_broken > 0: message.SetInfo( 'text', prefix + 'done! ' + HC.ConvertIntToPrettyString( num_broken ) + ' files caused errors, which have been written to the log.' )
else: message.SetInfo( 'text', prefix + 'done!' )
if num_broken > 0: job_key.SetVariable( 'popup_message_text_1', prefix + 'done! ' + HC.ConvertIntToPrettyString( num_broken ) + ' files caused errors, which have been written to the log.' )
else: job_key.SetVariable( 'popup_message_text_1', prefix + 'done!' )
HydrusThreading.CallToThread( THREADRegenerateThumbnails )
@ -1646,11 +1622,9 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
job_key = HC.JobKey( pausable = False, cancellable = False )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, url_string, job_key )
HC.pubsub.pub( 'message', job_key )
HC.pubsub.pub( 'message', message )
HydrusThreading.CallToThread( HydrusDownloading.THREADDownloadURL, message, url, url_string )
HydrusThreading.CallToThread( HydrusDownloading.THREADDownloadURL, job_key, url, url_string )

View File

@ -219,6 +219,9 @@ class Animation( wx.Window ):
if self._video_container.HasFrame( self._current_frame_index ): self._DrawFrame()
else: self._DrawWhite()
self._timer_video.Start( 0, wx.TIMER_ONE_SHOT )
@ -228,15 +231,26 @@ class Animation( wx.Window ):
self._current_frame_index = frame_index
self._video_container.SetFramePosition( self._current_frame_index )
self._current_frame_drawn_at = 0.0
self._current_frame_drawn = False
self._video_container.SetFramePosition( self._current_frame_index )
if self._video_container.HasFrame( self._current_frame_index ): self._DrawFrame()
else: self._DrawWhite()
self._timer_video.Start( 0, wx.TIMER_ONE_SHOT )
self._paused = True
def Play( self ): self._paused = False
def Play( self ):
self._paused = False
self._timer_video.Start( 0, wx.TIMER_ONE_SHOT )
def SetAnimationBar( self, animation_bar ): self._animation_bar = animation_bar
@ -266,11 +280,14 @@ class Animation( wx.Window ):
if not self._current_frame_drawn and self._video_container.HasFrame( self._current_frame_index ): self._DrawFrame()
ms_since_current_frame_drawn = int( 1000.0 * ( HC.GetNowPrecise() - self._current_frame_drawn_at ) )
ms_until_next_frame = max( MIN_TIMER_TIME, self._video_container.GetDuration( self._current_frame_index ) - ms_since_current_frame_drawn )
self._timer_video.Start( ms_until_next_frame, wx.TIMER_ONE_SHOT )
if not self._current_frame_drawn or not self._paused:
ms_since_current_frame_drawn = int( 1000.0 * ( HC.GetNowPrecise() - self._current_frame_drawn_at ) )
ms_until_next_frame = max( MIN_TIMER_TIME, self._video_container.GetDuration( self._current_frame_index ) - ms_since_current_frame_drawn )
self._timer_video.Start( ms_until_next_frame, wx.TIMER_ONE_SHOT )
@ -316,10 +333,24 @@ class AnimationBar( wx.Window ):
dc.DrawRectangle( 0, 0, my_width, ANIMATED_SCANBAR_HEIGHT )
#
dc.SetBrush( wx.Brush( wx.SystemSettings.GetColour( wx.SYS_COLOUR_SCROLLBAR ) ) )
dc.DrawRectangle( int( float( my_width - ANIMATED_SCANBAR_CARET_WIDTH ) * float( self._current_frame_index ) / float( self._num_frames - 1 ) ), 0, ANIMATED_SCANBAR_CARET_WIDTH, ANIMATED_SCANBAR_HEIGHT )
#
dc.SetFont( wx.SystemSettings.GetFont( wx.SYS_DEFAULT_GUI_FONT ) )
dc.SetTextForeground( wx.BLACK )
s = HC.ConvertIntToPrettyString( self._current_frame_index + 1 ) + '/' + HC.ConvertIntToPrettyString( self._num_frames )
( x, y ) = dc.GetTextExtent( s )
dc.DrawText( s, my_width - x - 3, 3 )
def EventMouse( self, event ):
@ -4031,19 +4062,20 @@ class StaticImage( wx.Window ):
( frame_width, frame_height ) = hydrus_bitmap.GetSize()
x_scale = my_width / float( frame_width )
y_scale = my_height / float( frame_height )
dc.SetUserScale( x_scale, y_scale )
wx_bitmap = hydrus_bitmap.GetWxBitmap()
if frame_height != my_height:
image = hydrus_bitmap.GetWxImage()
image = image.Scale( my_width, my_height, wx.IMAGE_QUALITY_HIGH )
wx_bitmap = wx.BitmapFromImage( image )
else: wx_bitmap = hydrus_bitmap.GetWxBitmap()
dc.DrawBitmap( wx_bitmap, 0, 0 )
wx.CallAfter( wx_bitmap.Destroy )
dc.SetUserScale( 1.0, 1.0 )
self._timer_render_wait.Stop()

View File

@ -2424,6 +2424,327 @@ class PopupDismissAll( PopupWindow ):
def SetNumMessages( self, num_messages_pending ): self._text.SetLabel( HC.ConvertIntToPrettyString( num_messages_pending ) + ' more messages' )
class PopupMessageNew( PopupWindow ):
def __init__( self, parent, job_key ):
PopupWindow.__init__( self, parent )
self._job_key = job_key
vbox = wx.BoxSizer( wx.VERTICAL )
self._title = FitResistantStaticText( self, style = wx.ALIGN_CENTER )
self._title.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._title.Hide()
self._text_1 = FitResistantStaticText( self )
self._text_1.Wrap( 380 )
self._text_1.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._text_1.Hide()
self._gauge_1 = Gauge( self, size = ( 380, -1 ) )
self._gauge_1.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._gauge_1.Hide()
self._text_2 = FitResistantStaticText( self )
self._text_2.Wrap( 380 )
self._text_2.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._text_2.Hide()
self._gauge_2 = Gauge( self, size = ( 380, -1 ) )
self._gauge_2.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._gauge_2.Hide()
self._show_files_button = wx.Button( self )
self._show_files_button.Bind( wx.EVT_BUTTON, self.EventShowFilesButton )
self._show_files_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._show_files_button.Hide()
self._error_text = FitResistantStaticText( self )
self._error_text.Wrap( 380 )
self._error_text.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._error_text.Hide()
self._show_tb_button = wx.Button( self, label = 'show traceback' )
self._show_tb_button.Bind( wx.EVT_BUTTON, self.EventShowTBButton )
self._show_tb_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._show_tb_button.Hide()
self._tb_text = FitResistantStaticText( self )
self._tb_text.Wrap( 380 )
self._tb_text.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._tb_text.Hide()
self._show_caller_tb_button = wx.Button( self, label = 'show caller traceback' )
self._show_caller_tb_button.Bind( wx.EVT_BUTTON, self.EventShowCallerTBButton )
self._show_caller_tb_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._show_caller_tb_button.Hide()
self._caller_tb_text = FitResistantStaticText( self )
self._caller_tb_text.Wrap( 380 )
self._caller_tb_text.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._caller_tb_text.Hide()
self._show_db_tb_button = wx.Button( self, label = 'show db traceback' )
self._show_db_tb_button.Bind( wx.EVT_BUTTON, self.EventShowDBTBButton )
self._show_db_tb_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._show_db_tb_button.Hide()
self._db_tb_text = FitResistantStaticText( self )
self._db_tb_text.Wrap( 380 )
self._db_tb_text.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._db_tb_text.Hide()
self._copy_tb_button = wx.Button( self, label = 'copy traceback information' )
self._copy_tb_button.Bind( wx.EVT_BUTTON, self.EventCopyTBButton )
self._copy_tb_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._copy_tb_button.Hide()
self._pause_button = wx.Button( self, label = 'pause' )
self._pause_button.Bind( wx.EVT_BUTTON, self.EventPauseButton )
self._pause_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._pause_button.Hide()
self._cancel_button = wx.Button( self, label = 'cancel' )
self._cancel_button.Bind( wx.EVT_BUTTON, self.EventCancelButton )
self._cancel_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._cancel_button.Hide()
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( self._pause_button, FLAGS_MIXED )
hbox.AddF( self._cancel_button, FLAGS_MIXED )
vbox.AddF( self._title, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._text_1, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._gauge_1, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._text_2, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._gauge_2, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._show_files_button, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._error_text, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._show_tb_button, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._tb_text, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._show_caller_tb_button, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._caller_tb_text, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._show_db_tb_button, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._db_tb_text, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._copy_tb_button, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( hbox, FLAGS_BUTTON_SIZER )
self.SetSizer( vbox )
def _ProcessText( self, text ):
if len( text ) > TEXT_CUTOFF:
new_text = 'Some text arrived that is too long to display here. Here is the start of it (the rest is printed to the log):'
new_text += os.linesep * 2
new_text += text[:TEXT_CUTOFF]
text = new_text
return text
def Dismiss( self ):
if self._job_key.IsCancellable():
import ClientGUIDialogs
message = 'Do you want to continue in the background, or stop right now?'
with ClientGUIDialogs.DialogYesNo( self, message, title = 'Choose if the job continues in the background.', yes_label = 'continue', no_label = 'stop' ) as dlg:
result = dlg.ShowModal()
if result == wx.ID_CANCEL: return
elif result == wx.ID_NO: self._job_key.Cancel()
if self._job_key.IsPaused(): self._job_key.Cancel()
PopupWindow.Dismiss( self )
def EventCancelButton( self, event ):
self._job_key.Cancel()
self._cancel_button.Disable()
def EventCopyTBButton( self, event ): HC.pubsub.pub( 'clipboard', 'text', self._tb_copy_text )
def EventPauseButton( self, event ):
if self._job_key.IsPaused():
self._job_key.Resume()
self._pause_button.SetLabel( 'pause' )
else:
self._job_key.Pause()
self._pause_button.SetLabel( 'resume' )
def EventShowCallerTBButton( self, event ):
if self._caller_tb_text.IsShown():
self._show_caller_tb_button.SetLabel( 'show caller traceback' )
self._caller_tb_text.Hide()
else:
self._show_caller_tb_button.SetLabel( 'hide caller traceback' )
self._caller_tb_text.Show()
self.GetParent().MakeSureEverythingFits()
def EventShowDBTBButton( self, event ):
if self._db_tb_text.IsShown():
self._show_db_tb_button.SetLabel( 'show db traceback' )
self._db_tb_text.Hide()
else:
self._show_db_tb_button.SetLabel( 'hide db traceback' )
self._db_tb_text.Show()
self.GetParent().MakeSureEverythingFits()
def EventShowFilesButton( self, event ):
hashes = self._job_key.GetVariable( 'popup_message_files' )
media_results = HC.app.Read( 'media_results', HC.LOCAL_FILE_SERVICE_KEY, hashes )
HC.pubsub.pub( 'new_page_query', HC.LOCAL_FILE_SERVICE_KEY, initial_media_results = media_results )
def EventShowTBButton( self, event ):
if self._tb_text.IsShown():
self._show_tb_button.SetLabel( 'show traceback' )
self._tb_text.Hide()
else:
self._show_tb_button.SetLabel( 'hide traceback' )
self._tb_text.Show()
self.GetParent().MakeSureEverythingFits()
def Update( self ):
if self._job_key.HasVariable( 'popup_message_title' ):
text = self._job_key.GetVariable( 'popup_message_title' )
if self._title.GetLabel() != text: self._title.SetLabel( text )
self._title.Show()
else: self._title.Hide()
if self._job_key.HasVariable( 'popup_message_text_1' ):
text = self._job_key.GetVariable( 'popup_message_text_1' )
if self._text_1.GetLabel() != text: self._text_1.SetLabel( self._ProcessText( HC.u( text ) ) )
self._text_1.Show()
else: self._text_1.Hide()
if self._job_key.HasVariable( 'popup_message_gauge_1' ):
( value, range ) = self._job_key.GetVariable( 'popup_message_gauge_1' )
if range is None or value is None: self._gauge_1.Pulse()
else:
self._gauge_1.SetRange( range )
self._gauge_1.SetValue( value )
self._gauge_1.Show()
else: self._gauge_1.Hide()
if self._job_key.HasVariable( 'popup_message_text_2' ):
text = self._job_key.GetVariable( 'popup_message_text_2' )
if self._text_2.GetLabel() != text: self._text_2.SetLabel( self._ProcessText( HC.u( text ) ) )
self._text_2.Show()
else: self._text_2.Hide()
if self._job_key.HasVariable( 'popup_message_gauge_2' ):
( value, range ) = self._job_key.GetVariable( 'popup_message_gauge_2' )
if range is None or value is None: self._gauge_2.Pulse()
else:
self._gauge_2.SetRange( range )
self._gauge_2.SetValue( value )
self._gauge_2.Show()
else: self._gauge_2.Hide()
if self._job_key.HasVariable( 'popup_message_files' ):
hashes = self._job_key.GetVariable( 'popup_message_files' )
text = 'show ' + HC.ConvertIntToPrettyString( len( hashes ) ) + ' files'
if self._show_files_button.GetLabel() != text: self._show_files_button.SetLabel( text )
self._show_files_button.Show()
else: self._show_files_button.Hide()
#vbox.AddF( self._error_text, FLAGS_EXPAND_PERPENDICULAR )
#vbox.AddF( self._show_tb_button, FLAGS_EXPAND_PERPENDICULAR )
#vbox.AddF( self._tb_text, FLAGS_EXPAND_PERPENDICULAR )
#vbox.AddF( self._show_caller_tb_button, FLAGS_EXPAND_PERPENDICULAR )
#vbox.AddF( self._caller_tb_text, FLAGS_EXPAND_PERPENDICULAR )
#vbox.AddF( self._show_db_tb_button, FLAGS_EXPAND_PERPENDICULAR )
#vbox.AddF( self._db_tb_text, FLAGS_EXPAND_PERPENDICULAR )
#vbox.AddF( self._copy_tb_button, FLAGS_EXPAND_PERPENDICULAR )
# pause + cancel buttons
class PopupMessage( PopupWindow ):
def __init__( self, parent, message ):
@ -2433,8 +2754,6 @@ class PopupMessage( PopupWindow ):
self._message = message
def IsClosed( self ): return self._message.IsClosed()
def Update( self ): pass
class PopupMessageDBError( PopupMessage ):
@ -2681,7 +3000,7 @@ class PopupMessageGauge( PopupMessage ):
def Dismiss( self ):
if not self._message.IsClosed() and self._message.GetInfo( 'mode' ) == 'cancelable gauge':
if self._message.GetInfo( 'mode' ) == 'cancelable gauge':
import ClientGUIDialogs
@ -2740,7 +3059,7 @@ class PopupMessageGauge( PopupMessage ):
mode = self._message.GetInfo( 'mode' )
text = self._message.GetInfo( 'text' )[:TEXT_CUTOFF]
if self._job_key.IsPausable() and self._created - HC.GetNow() > 2: self._pause_button.Show()
else: self._pause_button.Hide()
@ -2774,7 +3093,7 @@ class PopupMessageGauge( PopupMessage ):
range = self._message.GetInfo( 'range' )
value = self._message.GetInfo( 'value' )
if range is None or value is None: self._gauge.Pulse()
else:
@ -2857,7 +3176,6 @@ class PopupMessageManager( wx.Frame ):
self._SizeAndPositionAndShow()
HC.pubsub.sub( self, 'AddMessage', 'message' )
# maybe make a ding noise when a new message arrives
self._old_excepthook = sys.excepthook
self._old_show_exception = HC.ShowException
@ -2901,15 +3219,19 @@ class PopupMessageManager( wx.Frame ):
def _CreateMessageWindow( self, message ):
message_type = message.GetType()
if message_type == HC.MESSAGE_TYPE_TEXT: c = PopupMessageText
elif message_type == HC.MESSAGE_TYPE_ERROR: c = PopupMessageError
elif message_type == HC.MESSAGE_TYPE_DB_ERROR: c = PopupMessageDBError
elif message_type == HC.MESSAGE_TYPE_FILES: c = PopupMessageFiles
elif message_type == HC.MESSAGE_TYPE_GAUGE: c = PopupMessageGauge
window = c( self, message )
if type( message ) == HC.JobKey: window = PopupMessageNew( self, message )
else:
message_type = message.GetType()
if message_type == HC.MESSAGE_TYPE_TEXT: c = PopupMessageText
elif message_type == HC.MESSAGE_TYPE_ERROR: c = PopupMessageError
elif message_type == HC.MESSAGE_TYPE_DB_ERROR: c = PopupMessageDBError
elif message_type == HC.MESSAGE_TYPE_FILES: c = PopupMessageFiles
elif message_type == HC.MESSAGE_TYPE_GAUGE: c = PopupMessageGauge
window = c( self, message )
window.Update()
@ -2918,6 +3240,13 @@ class PopupMessageManager( wx.Frame ):
def _PrintMessage( self, message ):
if type( message ) == HC.JobKey:
# if job_key hasvariable title, then print...
return
message_type = message.GetType()
if message_type == HC.MESSAGE_TYPE_TEXT: message_string = HC.u( message.GetInfo( 'text' ) )
@ -2944,6 +3273,13 @@ class PopupMessageManager( wx.Frame ):
def _ShouldDisplayMessage( self, message ):
if type( message ) == HC.JobKey:
# do the same, but for job_key errors
return True
message_type = message.GetType()
if message_type == HC.MESSAGE_TYPE_ERROR:
@ -3013,12 +3349,7 @@ class PopupMessageManager( wx.Frame ):
self._CheckPending()
except:
traceback.print_stack()
print( traceback.format_exc() )
except: print( traceback.format_exc() )
def CleanBeforeDestroy( self ):
@ -3077,8 +3408,7 @@ class PopupMessageManager( wx.Frame ):
message_window = sizer_item.GetWindow()
if message_window.IsClosed(): self.Dismiss( message_window )
else: message_window.Update()
message_window.Update()
self.MakeSureEverythingFits()

View File

@ -117,6 +117,8 @@ class Dialog( wx.Dialog ):
if position == 'center': wx.CallAfter( self.Center )
HC.app.ResetIdleTimer()
def EventDialogButton( self, event ): self.EndModal( event.GetId() )
@ -5122,11 +5124,9 @@ class DialogSelectYoutubeURL( Dialog ):
job_key = HC.JobKey( pausable = False, cancellable = False )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, url_string, job_key )
HydrusThreading.CallToThread( HydrusDownloading.THREADDownloadURL, job_key, url, url_string )
HydrusThreading.CallToThread( HydrusDownloading.THREADDownloadURL, message, url, url_string )
HC.pubsub.pub( 'message', message )
HC.pubsub.pub( 'message', job_key )

View File

@ -2787,7 +2787,7 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
self._listbook = ClientGUICommon.ListBook( self )
# files and memory
# files and thumbnails
self._file_page = wx.Panel( self._listbook )
self._file_page.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
@ -2796,40 +2796,51 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
self._exclude_deleted_files = wx.CheckBox( self._file_page, label = '' )
self._thumbnail_cache_size = wx.SpinCtrl( self._file_page, min = 10, max = 3000 )
self._thumbnail_cache_size.Bind( wx.EVT_SPINCTRL, self.EventThumbnailsUpdate )
self._estimated_number_thumbnails = wx.StaticText( self._file_page, label = '' )
self._preview_cache_size = wx.SpinCtrl( self._file_page, min = 20, max = 3000 )
self._preview_cache_size.Bind( wx.EVT_SPINCTRL, self.EventPreviewsUpdate )
self._estimated_number_previews = wx.StaticText( self._file_page, label = '' )
self._fullscreen_cache_size = wx.SpinCtrl( self._file_page, min = 100, max = 3000 )
self._fullscreen_cache_size.Bind( wx.EVT_SPINCTRL, self.EventFullscreensUpdate )
self._estimated_number_fullscreens = wx.StaticText( self._file_page, label = '' )
self._thumbnail_width = wx.SpinCtrl( self._file_page, min=20, max=200 )
self._thumbnail_width.Bind( wx.EVT_SPINCTRL, self.EventThumbnailsUpdate )
self._thumbnail_height = wx.SpinCtrl( self._file_page, min=20, max=200 )
self._thumbnail_height.Bind( wx.EVT_SPINCTRL, self.EventThumbnailsUpdate )
self._num_autocomplete_chars = wx.SpinCtrl( self._file_page, min = 1, max = 100 )
self._listbook.AddPage( self._file_page, 'files and thumbnails' )
# maintenance and memory
self._maintenance_page = wx.Panel( self._listbook )
self._maintenance_page.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
self._thumbnail_cache_size = wx.SpinCtrl( self._maintenance_page, min = 10, max = 3000 )
self._thumbnail_cache_size.Bind( wx.EVT_SPINCTRL, self.EventThumbnailsUpdate )
self._estimated_number_thumbnails = wx.StaticText( self._maintenance_page, label = '' )
self._preview_cache_size = wx.SpinCtrl( self._maintenance_page, min = 20, max = 3000 )
self._preview_cache_size.Bind( wx.EVT_SPINCTRL, self.EventPreviewsUpdate )
self._estimated_number_previews = wx.StaticText( self._maintenance_page, label = '' )
self._fullscreen_cache_size = wx.SpinCtrl( self._maintenance_page, min = 100, max = 3000 )
self._fullscreen_cache_size.Bind( wx.EVT_SPINCTRL, self.EventFullscreensUpdate )
self._estimated_number_fullscreens = wx.StaticText( self._maintenance_page, label = '' )
self._maintenance_idle_period = wx.SpinCtrl( self._maintenance_page, min = 0, max = 1000 )
self._maintenance_vacuum_period = wx.SpinCtrl( self._maintenance_page, min = 0, max = 365 )
self._maintenance_delete_orphans_period = wx.SpinCtrl( self._maintenance_page, min = 0, max = 365 )
self._num_autocomplete_chars = wx.SpinCtrl( self._maintenance_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 = wx.SpinCtrl( self._maintenance_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 = wx.SpinCtrl( self._maintenance_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 = wx.SpinCtrl( self._maintenance_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' )
self._listbook.AddPage( self._maintenance_page, 'maintenance and memory' )
# gui
@ -3038,20 +3049,26 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
self._exclude_deleted_files.SetValue( HC.options[ 'exclude_deleted_files' ] )
self._thumbnail_cache_size.SetValue( int( HC.options[ 'thumbnail_cache_size' ] / 1048576 ) )
self._preview_cache_size.SetValue( int( HC.options[ 'preview_cache_size' ] / 1048576 ) )
self._fullscreen_cache_size.SetValue( int( HC.options[ 'fullscreen_cache_size' ] / 1048576 ) )
( thumbnail_width, thumbnail_height ) = HC.options[ 'thumbnail_dimensions' ]
self._thumbnail_width.SetValue( thumbnail_width )
self._thumbnail_height.SetValue( thumbnail_height )
#
self._thumbnail_cache_size.SetValue( int( HC.options[ 'thumbnail_cache_size' ] / 1048576 ) )
self._preview_cache_size.SetValue( int( HC.options[ 'preview_cache_size' ] / 1048576 ) )
self._fullscreen_cache_size.SetValue( int( HC.options[ 'fullscreen_cache_size' ] / 1048576 ) )
self._num_autocomplete_chars.SetValue( HC.options[ 'num_autocomplete_chars' ] )
self._maintenance_idle_period.SetValue( HC.options[ 'idle_period' ] / 60 )
self._maintenance_vacuum_period.SetValue( HC.options[ 'maintenance_vacuum_period' ] / 86400 )
self._maintenance_delete_orphans_period.SetValue( HC.options[ 'maintenance_delete_orphans_period' ] / 86400 )
( char_limit, long_wait, short_wait ) = HC.options[ 'ac_timings' ]
self._autocomplete_long_wait.SetValue( long_wait )
@ -3217,6 +3234,26 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
def ArrangeControls():
gridbox = wx.FlexGridSizer( 0, 2 )
gridbox.AddGrowableCol( 1, 1 )
gridbox.AddF( wx.StaticText( self._file_page, label = 'Default export directory: ' ), FLAGS_MIXED )
gridbox.AddF( self._export_location, FLAGS_EXPAND_BOTH_WAYS )
gridbox.AddF( wx.StaticText( self._file_page, label = 'Exclude deleted files from new imports and remote searches: ' ), FLAGS_MIXED )
gridbox.AddF( self._exclude_deleted_files, FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._file_page, label = 'Thumbnail width: ' ), FLAGS_MIXED )
gridbox.AddF( self._thumbnail_width, FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._file_page, label = 'Thumbnail height: ' ), FLAGS_MIXED )
gridbox.AddF( self._thumbnail_height, FLAGS_MIXED )
self._file_page.SetSizer( gridbox )
#
thumbnails_sizer = wx.BoxSizer( wx.HORIZONTAL )
thumbnails_sizer.AddF( self._thumbnail_cache_size, FLAGS_MIXED )
@ -3236,40 +3273,37 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
gridbox.AddGrowableCol( 1, 1 )
gridbox.AddF( wx.StaticText( self._file_page, label = 'Default export directory: ' ), FLAGS_MIXED )
gridbox.AddF( self._export_location, FLAGS_EXPAND_BOTH_WAYS )
gridbox.AddF( wx.StaticText( self._file_page, label = 'Exclude deleted files from new imports and remote searches: ' ), FLAGS_MIXED )
gridbox.AddF( self._exclude_deleted_files, FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._file_page, label = 'MB memory reserved for thumbnail cache: ' ), FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._maintenance_page, label = 'MB memory reserved for thumbnail cache: ' ), FLAGS_MIXED )
gridbox.AddF( thumbnails_sizer, FLAGS_NONE )
gridbox.AddF( wx.StaticText( self._file_page, label = 'MB memory reserved for preview cache: ' ), FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._maintenance_page, label = 'MB memory reserved for preview cache: ' ), FLAGS_MIXED )
gridbox.AddF( previews_sizer, FLAGS_NONE )
gridbox.AddF( wx.StaticText( self._file_page, label = 'MB memory reserved for fullscreen cache: ' ), FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._maintenance_page, label = 'MB memory reserved for fullscreen cache: ' ), FLAGS_MIXED )
gridbox.AddF( fullscreens_sizer, FLAGS_NONE )
gridbox.AddF( wx.StaticText( self._file_page, label = 'Thumbnail width: ' ), FLAGS_MIXED )
gridbox.AddF( self._thumbnail_width, FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._maintenance_page, label = 'Minutes of inactivity until client is considered idle (0 for never): ' ), FLAGS_MIXED )
gridbox.AddF( self._maintenance_idle_period, FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._file_page, label = 'Thumbnail height: ' ), FLAGS_MIXED )
gridbox.AddF( self._thumbnail_height, FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._maintenance_page, label = 'Number of days to wait between vacuums (0 for never): ' ), FLAGS_MIXED )
gridbox.AddF( self._maintenance_vacuum_period, FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._file_page, label = 'Autocomplete character threshold: ' ), FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._maintenance_page, label = 'Number of days to wait between orphan deletions (0 for never): ' ), FLAGS_MIXED )
gridbox.AddF( self._maintenance_delete_orphans_period, FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._maintenance_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( wx.StaticText( self._maintenance_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( wx.StaticText( self._maintenance_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( wx.StaticText( self._maintenance_page, label = 'Autocomplete short wait (ms): ' ), FLAGS_MIXED )
gridbox.AddF( self._autocomplete_short_wait, FLAGS_MIXED )
self._file_page.SetSizer( gridbox )
self._maintenance_page.SetSizer( gridbox )
#
@ -3539,7 +3573,7 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
self.EventPreviewsUpdate( None )
self.EventThumbnailsUpdate( None )
wx.CallAfter( self._file_page.Layout ) # draws the static texts correctly
wx.CallAfter( self._maintenance_page.Layout ) # draws the static texts correctly
wx.CallAfter( self._ok.SetFocus )
@ -3759,6 +3793,10 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
HC.options[ 'preview_cache_size' ] = self._preview_cache_size.GetValue() * 1048576
HC.options[ 'fullscreen_cache_size' ] = self._fullscreen_cache_size.GetValue() * 1048576
HC.options[ 'idle_period' ] = 60 * self._maintenance_idle_period.GetValue()
HC.options[ 'maintenance_delete_orphans_period' ] = 86400 * self._maintenance_delete_orphans_period.GetValue()
HC.options[ 'maintenance_vacuum_period' ] = 86400 * self._maintenance_vacuum_period.GetValue()
new_thumbnail_dimensions = [ self._thumbnail_width.GetValue(), self._thumbnail_height.GetValue() ]
if new_thumbnail_dimensions != HC.options[ 'thumbnail_dimensions' ]:

View File

@ -281,7 +281,16 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
else: s = HC.ConvertIntToPrettyString( num_files ) + ' files'
elif num_selected == 1: s = '1 of ' + HC.ConvertIntToPrettyString( num_files ) + ' files selected, ' + pretty_total_size
else: s = HC.ConvertIntToPrettyString( num_selected ) + ' of ' + HC.ConvertIntToPrettyString( num_files ) + ' files selected, totalling ' + pretty_total_size
else:
num_inbox = sum( ( media.GetNumInbox() for media in self._selected_media ) )
if num_inbox == num_selected: inbox_phrase = 'all in inbox, '
elif num_inbox == 0: inbox_phrase = 'all archived, '
else: inbox_phrase = HC.ConvertIntToPrettyString( num_inbox ) + ' in inbox and ' + HC.ConvertIntToPrettyString( num_selected - num_inbox ) + ' archived, '
s = HC.ConvertIntToPrettyString( num_selected ) + ' of ' + HC.ConvertIntToPrettyString( num_files ) + ' files selected, ' + inbox_phrase + 'totalling ' + pretty_total_size
return s

View File

@ -565,9 +565,11 @@ class MediaCollection( MediaList, Media ):
def GetNumFiles( self ): return len( self._hashes )
def GetNumFrames( self ): return sum( [ media.GetNumFrames() for media in self._sorted_media ] )
def GetNumInbox( self ): return sum( ( media.GetNumInbox() for media in self._sorted_media ) )
def GetNumWords( self ): return sum( [ media.GetNumWords() for media in self._sorted_media ] )
def GetNumFrames( self ): return sum( ( media.GetNumFrames() for media in self._sorted_media ) )
def GetNumWords( self ): return sum( ( media.GetNumWords() for media in self._sorted_media ) )
def GetPrettyAge( self ): return 'imported ' + HC.ConvertTimestampToPrettyAgo( self._timestamp )
@ -681,6 +683,11 @@ class MediaSingleton( Media ):
def GetNumFrames( self ): return self._media_result.GetNumFrames()
def GetNumInbox( self ):
if self.HasInbox(): return 1
else: return 0
def GetNumWords( self ): return self._media_result.GetNumWords()
def GetTimestamp( self ):

View File

@ -65,7 +65,7 @@ options = {}
# Misc
NETWORK_VERSION = 15
SOFTWARE_VERSION = 137
SOFTWARE_VERSION = 138
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )
@ -1962,7 +1962,10 @@ class JobKey( object ):
def DeleteVariable( self, name ):
with self._variable_lock: del self._variables[ name ]
with self._variable_lock:
if name in self._variables: del self._variables[ name ]
def Finish( self ): self._done.set()
@ -2076,9 +2079,10 @@ class JobNetwork( object ):
class Message( object ):
def __init__( self, message_type, info ):
def __init__( self, message_type, job_key, info ):
self._message_type = message_type
self._job_key = job_key
self._info = info
self._closed = False
@ -2111,7 +2115,7 @@ class MessageGauge( Message ):
def __init__( self, message_type, text, job_key ):
Message.__init__( self, message_type, {} )
Message.__init__( self, message_type, job_key, {} )
self._info[ 'mode' ] = 'text'
self._info[ 'text' ] = text

View File

@ -1786,7 +1786,7 @@ class ImportQueueGeneratorThread( ImportQueueGenerator ):
finally: self._job_key.Finish()
def THREADDownloadURL( message, url, url_string ):
def THREADDownloadURL( job_key, url, url_string ):
try:
@ -1795,42 +1795,28 @@ def THREADDownloadURL( message, url, url_string ):
if range is None: text = url_string + ' - ' + HC.ConvertIntToBytes( value )
else: text = url_string + ' - ' + HC.ConvertIntToBytes( value ) + '/' + HC.ConvertIntToBytes( range )
message.SetInfo( 'range', range )
message.SetInfo( 'value', value )
message.SetInfo( 'text', text )
job_key.SetVariable( 'popup_message_text_1', text )
job_key.SetVariable( 'popup_message_gauge_1', ( value, range ) )
message.SetInfo( 'range', None )
message.SetInfo( 'value', None )
message.SetInfo( 'mode', 'gauge' )
temp_path = HC.http.Request( HC.GET, url, response_to_path = True, report_hooks = [ hook ] )
message.SetInfo( 'range', None )
message.SetInfo( 'value', None )
message.SetInfo( 'text', 'importing ' + url_string )
message.SetInfo( 'mode', 'gauge' )
job_key.DeleteVariable( 'popup_message_gauge_1' )
job_key.SetVariable( 'popup_message_text_1', 'importing ' + url_string )
( result, hash ) = HC.app.WriteSynchronous( 'import_file', temp_path )
if result in ( 'successful', 'redundant' ):
message.SetInfo( 'text', url_string )
message.SetInfo( 'hashes', { hash } )
message.SetInfo( 'mode', 'files' )
job_key.SetVariable( 'popup_message_text_1', url_string )
job_key.SetVariable( 'popup_message_files', { hash } )
elif result == 'deleted':
message.SetInfo( 'text', 'File was already deleted!' )
message.SetInfo( 'mode', 'text' )
job_key.SetVariable( 'popup_message_text_1', url_string + ' was already deleted!' )
except Exception as e:
message.Close()
HC.ShowException( e )
except Exception as e: HC.ShowException( e )
def Parse4chanPostScreen( html ):

View File

@ -550,6 +550,23 @@ class HydrusBitmap( object ):
else: return wx.BitmapFromBufferRGBA( width, height, lz4.loads( self._data ) )
def GetWxImage( self ):
( width, height ) = self._size
if self._format == wx.BitmapBufferFormat_RGB: return wx.ImageFromBuffer( width, height, lz4.loads( self._data ) )
else:
bitmap = wx.BitmapFromBufferRGBA( width, height, lz4.loads( self._data ) )
image = wx.ImageFromBitmap( bitmap )
wx.CallAfter( bitmap.Destroy )
return image
def GetEstimatedMemoryFootprint( self ): return len( self._data )
def GetSize( self ): return self._size

View File

@ -2193,10 +2193,14 @@ class DB( ServiceDB ):
self._c.execute( 'ANALYZE' )
self._c.close()
self._db.close()
self._InitDBCursor()
self._c.execute( 'BEGIN IMMEDIATE' )
shutil.copy( self._db_path, self._db_path + '.backup' )
if os.path.exists( self._db_path + '-wal' ): shutil.copy( self._db_path + '-wal', self._db_path + '-wal.backup' )
shutil.rmtree( HC.SERVER_FILES_DIR + '_backup', ignore_errors = True )
shutil.rmtree( HC.SERVER_THUMBNAILS_DIR + '_backup', ignore_errors = True )

View File

@ -46,7 +46,7 @@ class TestDaemons( unittest.TestCase ):
self.assertEqual( len( import_file ), 3 )
expected_tag_part = {'service_keys_to_tags': {HC.LOCAL_TAG_SERVICE_KEY: set(['local tag'])}}
expected_tag_part = { 'service_keys_to_tags' : { HC.LOCAL_TAG_SERVICE_KEY : set( [ 'local tag' ] ) } }
( one, two, three ) = import_file

View File

@ -131,6 +131,8 @@ class App( wx.App ):
def ReadDaemon( self, name, *args, **kwargs ): return self.Read( name )
def ResetIdleTimer( self ): pass
def SetRead( self, name, value ): self._reads[ name ] = value
def SetWebCookies( self, name, value ): self._cookies[ name ] = value