Version 249
This commit is contained in:
parent
7181b82ad7
commit
6e2e6832de
|
@ -8,6 +8,42 @@
|
|||
<div class="content">
|
||||
<h3>changelog</h3>
|
||||
<ul>
|
||||
<li><h3>version 249</h3></li>
|
||||
<ul>
|
||||
<li>reintroduced shape and colour options to edit ratings service panels</li>
|
||||
<li>reintroduced num_stars and allow_zero options to edit numerical ratings service panels</li>
|
||||
<li>the export phrase--defaulting to '{hash}'--will now persist through export dialogs. it is saved whenever you click update or export</li>
|
||||
<li>removed the unintended 'counts' that were appearing after related tags</li>
|
||||
<li>fixed 'remove' action in custom filters</li>
|
||||
<li>hitting the delete key on manage tags taglist now will always remove</li>
|
||||
<li>added a BUGFIX option to not verify regular https traffic on the old networking engine for those non-Windows users who are getting SSL verify errors</li>
|
||||
<li>refactored the top hover frame more, making it more flexible</li>
|
||||
<li>created a new top hover frame for the duplicates filter</li>
|
||||
<li>duplicates filter now also supports tag and ratings hover frames</li>
|
||||
<li>duplicates filter now reports A or B as file index</li>
|
||||
<li>added some placeholder buttons to the duplicates filter for actions and 'cog' customisation</li>
|
||||
<li>reduced duplicate search shutdown logspam</li>
|
||||
<li>improved duplicate search job cleanup</li>
|
||||
<li>improved mime detection of thumbnail regeneration</li>
|
||||
<li>improved some shutdown error handling</li>
|
||||
<li>improved numerical rating search accuracy</li>
|
||||
<li>improved some hdd import error handling</li>
|
||||
<li>improved some unicode error handling</li>
|
||||
<li>improved reliability of some database transaction processing</li>
|
||||
<li>fixed animationbar having problems with single-frame videos</li>
|
||||
<li>fixed namespace colour taglist not updating colour correctly</li>
|
||||
<li>stopped the namespace colour taglist from deleting default namespace colours</li>
|
||||
<li>made the new class of button more compact--not sure if I like it</li>
|
||||
<li>refactored some db initialisation to avoid future transaction problems during special updates</li>
|
||||
<li>tidied up some last incomplete taglist code from last week</li>
|
||||
<li>did a little prep for some future shortucts overhaul</li>
|
||||
<li>did some more menu code updating</li>
|
||||
<li>added a simple subscription save/load unit test</li>
|
||||
<li>moved outdated server unit tests forward</li>
|
||||
<li>fleshed out some server certificate generation</li>
|
||||
<li>some other misc v245 catchup work</li>
|
||||
<li>cleaned up some pydeadobjecterrors caused by downloaders reporting progress to destroyed windows</li>
|
||||
</ul>
|
||||
<li><h3>version 248</h3></li>
|
||||
<ul>
|
||||
<li>fixed two more issues with recent update code!</li>
|
||||
|
|
|
@ -1088,7 +1088,14 @@ class ClientFilesManager( object ):
|
|||
|
||||
( base, filename ) = os.path.split( path )
|
||||
|
||||
( hash_encoded, ext ) = filename.split( '.', 1 )
|
||||
if '.' in filename:
|
||||
|
||||
( hash_encoded, ext ) = filename.split( '.', 1 )
|
||||
|
||||
else:
|
||||
|
||||
continue # it is an update file, so let's save us some ffmpeg lag and logspam
|
||||
|
||||
|
||||
hash = hash_encoded.decode( 'hex' )
|
||||
|
||||
|
|
|
@ -715,9 +715,15 @@ class Controller( HydrusController.HydrusController ):
|
|||
self.WriteInterruptable( 'maintain_similar_files_duplicate_pairs', search_distance, stop_time = search_stop_time, abandon_if_other_work_to_do = True )
|
||||
|
||||
|
||||
self.WriteInterruptable( 'vacuum', stop_time = stop_time )
|
||||
if stop_time is None or not HydrusData.TimeHasPassed( stop_time ):
|
||||
|
||||
self.WriteInterruptable( 'vacuum', stop_time = stop_time )
|
||||
|
||||
|
||||
self.WriteInterruptable( 'analyze', stop_time = stop_time )
|
||||
if stop_time is None or not HydrusData.TimeHasPassed( stop_time ):
|
||||
|
||||
self.WriteInterruptable( 'analyze', stop_time = stop_time )
|
||||
|
||||
|
||||
if stop_time is None or not HydrusData.TimeHasPassed( stop_time ):
|
||||
|
||||
|
@ -991,7 +997,14 @@ class Controller( HydrusController.HydrusController ):
|
|||
|
||||
if HydrusGlobals.do_idle_shutdown_work:
|
||||
|
||||
self.DoIdleShutdownWork()
|
||||
try:
|
||||
|
||||
self.DoIdleShutdownWork()
|
||||
|
||||
except:
|
||||
|
||||
ClientData.ReportShutdownException()
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1147,14 +1160,7 @@ class Controller( HydrusController.HydrusController ):
|
|||
except HydrusExceptions.ShutdownException: pass
|
||||
except:
|
||||
|
||||
text = 'A serious error occured while trying to exit the program. Its traceback may be shown next. It should have also been written to client.log. You may need to quit the program from task manager.'
|
||||
|
||||
HydrusData.DebugPrint( text )
|
||||
|
||||
HydrusData.DebugPrint( traceback.format_exc() )
|
||||
|
||||
wx.CallAfter( wx.MessageBox, traceback.format_exc() )
|
||||
wx.CallAfter( wx.MessageBox, text )
|
||||
ClientData.ReportShutdownException()
|
||||
|
||||
finally:
|
||||
|
||||
|
|
|
@ -488,7 +488,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
job_key.SetVariable( 'popup_text_1', 'closing db' )
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._CloseDBCursor()
|
||||
|
||||
|
@ -517,7 +517,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._InitDBCursor()
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
|
||||
job_key.SetVariable( 'popup_text_1', 'done!' )
|
||||
|
@ -1059,56 +1059,65 @@ class DB( HydrusDB.HydrusDB ):
|
|||
pub_job_key = True
|
||||
|
||||
|
||||
( total_num_hash_ids_in_cache, ) = self._c.execute( 'SELECT COUNT( * ) FROM shape_search_cache;' ).fetchone()
|
||||
|
||||
hash_ids = [ hash_id for ( hash_id, ) in self._c.execute( 'SELECT hash_id FROM shape_search_cache WHERE searched_distance IS NULL or searched_distance < ?;', ( search_distance, ) ) ]
|
||||
|
||||
pairs_found = 0
|
||||
|
||||
total_done_previously = total_num_hash_ids_in_cache - len( hash_ids )
|
||||
|
||||
for ( i, hash_id ) in enumerate( hash_ids ):
|
||||
try:
|
||||
|
||||
job_key.SetVariable( 'popup_title', 'similar files duplicate pair discovery' )
|
||||
( total_num_hash_ids_in_cache, ) = self._c.execute( 'SELECT COUNT( * ) FROM shape_search_cache;' ).fetchone()
|
||||
|
||||
if pub_job_key and not job_key_pubbed:
|
||||
hash_ids = [ hash_id for ( hash_id, ) in self._c.execute( 'SELECT hash_id FROM shape_search_cache WHERE searched_distance IS NULL or searched_distance < ?;', ( search_distance, ) ) ]
|
||||
|
||||
pairs_found = 0
|
||||
|
||||
total_done_previously = total_num_hash_ids_in_cache - len( hash_ids )
|
||||
|
||||
for ( i, hash_id ) in enumerate( hash_ids ):
|
||||
|
||||
self._controller.pub( 'message', job_key )
|
||||
job_key.SetVariable( 'popup_title', 'similar files duplicate pair discovery' )
|
||||
|
||||
job_key_pubbed = True
|
||||
if pub_job_key and not job_key_pubbed:
|
||||
|
||||
self._controller.pub( 'message', job_key )
|
||||
|
||||
job_key_pubbed = True
|
||||
|
||||
|
||||
( i_paused, should_quit ) = job_key.WaitIfNeeded()
|
||||
|
||||
should_stop = stop_time is not None and HydrusData.TimeHasPassed( stop_time )
|
||||
|
||||
if should_quit or should_stop:
|
||||
|
||||
return
|
||||
|
||||
|
||||
text = 'searched ' + HydrusData.ConvertValueRangeToPrettyString( total_done_previously + i, total_num_hash_ids_in_cache ) + ' files, found ' + HydrusData.ConvertIntToPrettyString( pairs_found ) + ' potential duplicate pairs'
|
||||
|
||||
job_key.SetVariable( 'popup_text_1', text )
|
||||
job_key.SetVariable( 'popup_gauge_1', ( total_done_previously + i, total_num_hash_ids_in_cache ) )
|
||||
|
||||
if i % 100 == 0:
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'splash_set_status_text', text )
|
||||
|
||||
|
||||
duplicate_hash_ids = [ duplicate_hash_id for duplicate_hash_id in self._CacheSimilarFilesSearch( hash_id, search_distance ) if duplicate_hash_id != hash_id ]
|
||||
|
||||
# double-check the files exist in shape_search_cache, as I think stale branches are producing deleted file pairs here
|
||||
|
||||
self._c.executemany( 'INSERT OR IGNORE INTO duplicate_pairs ( smaller_hash_id, larger_hash_id, duplicate_type ) VALUES ( ?, ?, ? );', ( ( min( hash_id, duplicate_hash_id ), max( hash_id, duplicate_hash_id ), HC.DUPLICATE_UNKNOWN ) for duplicate_hash_id in duplicate_hash_ids ) )
|
||||
|
||||
pairs_found += self._GetRowCount()
|
||||
|
||||
self._c.execute( 'UPDATE shape_search_cache SET searched_distance = ? WHERE hash_id = ?;', ( search_distance, hash_id ) )
|
||||
|
||||
|
||||
( i_paused, should_quit ) = job_key.WaitIfNeeded()
|
||||
finally:
|
||||
|
||||
should_stop = stop_time is not None and HydrusData.TimeHasPassed( stop_time )
|
||||
job_key.SetVariable( 'popup_text_1', 'done!' )
|
||||
job_key.DeleteVariable( 'popup_gauge_1' )
|
||||
|
||||
if should_quit or should_stop:
|
||||
|
||||
return
|
||||
|
||||
job_key.Finish()
|
||||
job_key.Delete( 30 )
|
||||
|
||||
text = 'searched ' + HydrusData.ConvertValueRangeToPrettyString( total_done_previously + i, total_num_hash_ids_in_cache ) + ' files, found ' + HydrusData.ConvertIntToPrettyString( pairs_found ) + ' potential duplicate pairs'
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'splash_set_status_text', text )
|
||||
job_key.SetVariable( 'popup_text_1', text )
|
||||
job_key.SetVariable( 'popup_gauge_1', ( total_done_previously + i, total_num_hash_ids_in_cache ) )
|
||||
|
||||
duplicate_hash_ids = [ duplicate_hash_id for duplicate_hash_id in self._CacheSimilarFilesSearch( hash_id, search_distance ) if duplicate_hash_id != hash_id ]
|
||||
|
||||
# double-check the files exist in shape_search_cache, as I think stale branches are producing deleted file pairs here
|
||||
|
||||
self._c.executemany( 'INSERT OR IGNORE INTO duplicate_pairs ( smaller_hash_id, larger_hash_id, duplicate_type ) VALUES ( ?, ?, ? );', ( ( min( hash_id, duplicate_hash_id ), max( hash_id, duplicate_hash_id ), HC.DUPLICATE_UNKNOWN ) for duplicate_hash_id in duplicate_hash_ids ) )
|
||||
|
||||
pairs_found += self._GetRowCount()
|
||||
|
||||
self._c.execute( 'UPDATE shape_search_cache SET searched_distance = ? WHERE hash_id = ?;', ( search_distance, hash_id ) )
|
||||
|
||||
|
||||
job_key.SetVariable( 'popup_text_1', 'done!' )
|
||||
job_key.DeleteVariable( 'popup_gauge_1' )
|
||||
|
||||
job_key.Finish()
|
||||
job_key.Delete( 30 )
|
||||
|
||||
|
||||
def _CacheSimilarFilesMaintainFiles( self, job_key = None, stop_time = None ):
|
||||
|
@ -2078,7 +2087,10 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
HydrusDB.SetupDBCreatePragma( self._c, no_wal = self._no_wal )
|
||||
|
||||
try: self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
try:
|
||||
|
||||
self._BeginImmediate()
|
||||
|
||||
except Exception as e:
|
||||
|
||||
raise HydrusExceptions.DBAccessException( HydrusData.ToUnicode( e ) )
|
||||
|
@ -2246,7 +2258,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._c.executemany( 'INSERT INTO json_dumps_named VALUES ( ?, ?, ?, ? );', ClientDefaults.GetDefaultScriptRows() )
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
|
||||
def _DeleteFiles( self, service_id, hash_ids ):
|
||||
|
@ -3536,8 +3548,24 @@ class DB( HydrusDB.HydrusDB ):
|
|||
elif value == 'not rated': query_hash_ids.difference_update( [ hash_id for ( hash_id, ) in self._c.execute( 'SELECT hash_id FROM local_ratings WHERE service_id = ?;', ( service_id, ) ) ] )
|
||||
else:
|
||||
|
||||
if operator == u'\u2248': predicate = str( value * 0.95 ) + ' < rating AND rating < ' + str( value * 1.05 )
|
||||
else: predicate = 'rating ' + operator + ' ' + str( value )
|
||||
# floats are a pain!
|
||||
|
||||
if operator == u'\u2248':
|
||||
|
||||
predicate = str( value * 0.8 ) + ' < rating AND rating < ' + str( value * 1.2 )
|
||||
|
||||
elif operator == '<':
|
||||
|
||||
predicate = 'rating < ' + str( value * 0.995 )
|
||||
|
||||
elif operator == '>':
|
||||
|
||||
predicate = 'rating > ' + str( value * 1.005 )
|
||||
|
||||
elif operator == '=':
|
||||
|
||||
predicate = str( value * 0.995 ) + ' < rating AND rating < ' + str( value * 1.005 )
|
||||
|
||||
|
||||
query_hash_ids.intersection_update( [ hash_id for ( hash_id, ) in self._c.execute( 'SELECT hash_id FROM local_ratings WHERE service_id = ? AND ' + predicate + ';', ( service_id, ) ) ] )
|
||||
|
||||
|
@ -5581,19 +5609,6 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
def _InitCaches( self ):
|
||||
|
||||
new_options = self._GetJSONDump( HydrusSerialisable.SERIALISABLE_TYPE_CLIENT_OPTIONS )
|
||||
|
||||
disk_cache_init_period = new_options.GetNoneableInteger( 'disk_cache_init_period' )
|
||||
|
||||
if disk_cache_init_period is not None:
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'splash_set_status_text', 'preparing disk cache' )
|
||||
|
||||
stop_time = HydrusData.GetNow() + disk_cache_init_period
|
||||
|
||||
self._LoadIntoDiskCache( stop_time = stop_time )
|
||||
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'splash_set_status_text', 'preparing db caches' )
|
||||
|
||||
self._local_file_service_id = self._GetServiceId( CC.LOCAL_FILE_SERVICE_KEY )
|
||||
|
@ -5612,6 +5627,22 @@ class DB( HydrusDB.HydrusDB ):
|
|||
self._inbox_hash_ids = { id for ( id, ) in self._c.execute( 'SELECT hash_id FROM file_inbox;' ) }
|
||||
|
||||
|
||||
def _InitDiskCache( self ):
|
||||
|
||||
new_options = self._GetJSONDump( HydrusSerialisable.SERIALISABLE_TYPE_CLIENT_OPTIONS )
|
||||
|
||||
disk_cache_init_period = new_options.GetNoneableInteger( 'disk_cache_init_period' )
|
||||
|
||||
if disk_cache_init_period is not None:
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'splash_set_status_text', 'preparing disk cache' )
|
||||
|
||||
stop_time = HydrusData.GetNow() + disk_cache_init_period
|
||||
|
||||
self._LoadIntoDiskCache( stop_time = stop_time )
|
||||
|
||||
|
||||
|
||||
def _InitExternalDatabases( self ):
|
||||
|
||||
self._db_filenames[ 'external_caches' ] = 'client.caches.db'
|
||||
|
@ -6089,11 +6120,11 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
if previous_journal_mode == 'wal' and not self._fast_big_transaction_wal:
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._c.execute( 'PRAGMA journal_mode = TRUNCATE;' )
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
|
||||
c_u_p_num_rows = content_update_package.GetNumRows()
|
||||
|
@ -6137,11 +6168,11 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
if previous_journal_mode == 'wal' and not self._fast_big_transaction_wal:
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._c.execute( 'PRAGMA journal_mode = WAL;' )
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
|
||||
return ( False, c_u_p_total_weight_processed )
|
||||
|
@ -6182,11 +6213,11 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
if previous_journal_mode == 'wal' and not self._fast_big_transaction_wal:
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._c.execute( 'PRAGMA journal_mode = WAL;' )
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
|
||||
return ( True, c_u_p_total_weight_processed )
|
||||
|
@ -6856,11 +6887,11 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
stop_time = HydrusData.GetNow() + min( 5 + num_updates_to_do, 30 )
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._LoadIntoDiskCache( stop_time = stop_time )
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
num_updates_done = 0
|
||||
|
||||
|
@ -7128,7 +7159,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
def _ResetRepository( self, service ):
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
if not self._fast_big_transaction_wal:
|
||||
|
||||
|
@ -7137,7 +7168,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._c.execute( 'PRAGMA foreign_keys = ON;' )
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
( service_key, service_type, name, dictionary ) = service.ToTuple()
|
||||
|
||||
|
@ -7164,11 +7195,11 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
job_key.SetVariable( 'popup_text_1', prefix + ': done!' )
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._InitDBCursor()
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
job_key.Finish()
|
||||
|
||||
|
@ -7800,7 +7831,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._controller.pub( 'splash_set_status_text', 'committing to disk' )
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._CloseDBCursor()
|
||||
|
||||
|
@ -7830,7 +7861,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._InitDBCursor()
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
|
||||
for schema in [ 'main', 'external_caches', 'external_master', 'external_mappings' ]:
|
||||
|
@ -7854,11 +7885,11 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
if foreign_keys_on:
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._c.execute( 'PRAGMA foreign_keys = ?;', ( False, ) )
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
|
||||
self._controller.pub( 'splash_set_status_text', 'updating services' )
|
||||
|
@ -8037,7 +8068,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
text = 'Was unable to parse the tag: ' + HydrusData.ToUnicode( tag )
|
||||
text += os.linesep * 2
|
||||
text += str( e )
|
||||
text += HydrusData.ToUnicode( e )
|
||||
|
||||
raise Exception( text )
|
||||
|
||||
|
@ -8080,8 +8111,6 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._InitCaches()
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
|
||||
# due to a previous update, some clients have two entries per prefix with ..\db\client_files vs client_files type superfluous stuff.
|
||||
# let's clean it up nicely, catching any other weirdness along the way
|
||||
|
||||
|
@ -8285,8 +8314,6 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._InitCaches()
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
|
||||
self._controller.pub( 'splash_set_status_text', 'cleaning tags again' )
|
||||
|
||||
tag_service_ids = [ service_id for ( service_id, ) in self._c.execute( 'SELECT service_id FROM services WHERE service_type IN ( ?, ? );', ( HC.TAG_REPOSITORY, HC.LOCAL_TAG ) ) ]
|
||||
|
@ -8785,7 +8812,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
def _UpdateServices( self, services ):
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
if not self._fast_big_transaction_wal:
|
||||
|
||||
|
@ -8794,7 +8821,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._c.execute( 'PRAGMA foreign_keys = ON;' )
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
current_service_keys = { service_key for ( service_key, ) in self._c.execute( 'SELECT service_key FROM services;' ) }
|
||||
|
||||
|
@ -8831,11 +8858,11 @@ class DB( HydrusDB.HydrusDB ):
|
|||
self.pub_after_commit( 'notify_new_services_gui' )
|
||||
self.pub_after_commit( 'notify_new_pending' )
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._InitDBCursor()
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
|
||||
def _Vacuum( self, stop_time = None, force_vacuum = False ):
|
||||
|
@ -8866,7 +8893,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
if len( due_names ) > 0:
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
job_key_pubbed = False
|
||||
|
||||
|
@ -8927,7 +8954,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._InitDBCursor()
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
new_options.SetNoneableInteger( 'maintenance_vacuum_period_days', None )
|
||||
|
||||
|
@ -8943,7 +8970,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._InitDBCursor()
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
self._c.executemany( 'DELETE FROM vacuum_timestamps WHERE name = ?;', ( ( name, ) for name in names_done ) )
|
||||
|
||||
|
|
|
@ -346,6 +346,17 @@ def MergePredicates( predicates, add_namespaceless = False ):
|
|||
|
||||
return master_predicate_dict.values()
|
||||
|
||||
def ReportShutdownException():
|
||||
|
||||
text = 'A serious error occured while trying to exit the program. Its traceback may be shown next. It should have also been written to client.log. You may need to quit the program from task manager.'
|
||||
|
||||
HydrusData.DebugPrint( text )
|
||||
|
||||
HydrusData.DebugPrint( traceback.format_exc() )
|
||||
|
||||
wx.CallAfter( wx.MessageBox, traceback.format_exc() )
|
||||
wx.CallAfter( wx.MessageBox, text )
|
||||
|
||||
def ShowExceptionClient( e ):
|
||||
|
||||
( etype, value, tb ) = sys.exc_info()
|
||||
|
@ -563,6 +574,8 @@ class ClientOptions( HydrusSerialisable.SerialisableBase ):
|
|||
|
||||
self._dictionary[ 'booleans' ][ 'show_namespaces' ] = True
|
||||
|
||||
self._dictionary[ 'booleans' ][ 'verify_regular_https' ] = True
|
||||
|
||||
#
|
||||
|
||||
self._dictionary[ 'integers' ] = {}
|
||||
|
@ -607,6 +620,7 @@ class ClientOptions( HydrusSerialisable.SerialisableBase ):
|
|||
|
||||
self._dictionary[ 'strings' ][ 'main_gui_title' ] = 'hydrus client'
|
||||
self._dictionary[ 'strings' ][ 'namespace_connector' ] = ':'
|
||||
self._dictionary[ 'strings' ][ 'export_phrase' ] = '{hash}'
|
||||
|
||||
#
|
||||
|
||||
|
@ -1481,6 +1495,8 @@ class Shortcuts( HydrusSerialisable.SerialisableBaseNamed ):
|
|||
self._mouse_actions = {}
|
||||
self._keyboard_actions = {}
|
||||
|
||||
# update this to have actions as a separate serialisable class
|
||||
|
||||
|
||||
def _ConvertActionToSerialisableAction( self, action ):
|
||||
|
||||
|
|
|
@ -194,7 +194,7 @@ class ExportFolder( HydrusSerialisable.SerialisableBaseNamed ):
|
|||
SERIALISABLE_TYPE = HydrusSerialisable.SERIALISABLE_TYPE_EXPORT_FOLDER
|
||||
SERIALISABLE_VERSION = 2
|
||||
|
||||
def __init__( self, name, path = '', export_type = HC.EXPORT_FOLDER_TYPE_REGULAR, file_search_context = None, period = 3600, phrase = '{hash}' ):
|
||||
def __init__( self, name, path = '', export_type = HC.EXPORT_FOLDER_TYPE_REGULAR, file_search_context = None, period = 3600, phrase = None ):
|
||||
|
||||
HydrusSerialisable.SerialisableBaseNamed.__init__( self, name )
|
||||
|
||||
|
@ -203,6 +203,13 @@ class ExportFolder( HydrusSerialisable.SerialisableBaseNamed ):
|
|||
file_search_context = ClientSearch.FileSearchContext( file_service_key = CC.LOCAL_FILE_SERVICE_KEY )
|
||||
|
||||
|
||||
if phrase is None:
|
||||
|
||||
new_options = HydrusGlobals.client_controller.GetNewOptions()
|
||||
|
||||
phrase = new_options.GetString( 'export_phrase' )
|
||||
|
||||
|
||||
self._path = path
|
||||
self._export_type = export_type
|
||||
self._file_search_context = file_search_context
|
||||
|
|
|
@ -1851,7 +1851,10 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
|
|||
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
|
||||
try: account_key = dlg.GetValue().decode( 'hex' )
|
||||
try:
|
||||
|
||||
account_key = dlg.GetValue().decode( 'hex' )
|
||||
|
||||
except:
|
||||
|
||||
wx.MessageBox( 'Could not parse that account key' )
|
||||
|
@ -1859,9 +1862,9 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
|
|||
return
|
||||
|
||||
|
||||
subject_identifiers = ( HydrusData.AccountIdentifier( account_key = account_key ), )
|
||||
subject_account = 'blah' # fetch account from service
|
||||
|
||||
with ClientGUIDialogs.DialogModifyAccounts( self, service_key, subject_identifiers ) as dlg2: dlg2.ShowModal()
|
||||
with ClientGUIDialogs.DialogModifyAccounts( self, service_key, [ subject_account ] ) as dlg2: dlg2.ShowModal()
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import ClientConstants as CC
|
|||
import ClientData
|
||||
import ClientGUICommon
|
||||
import ClientGUIListBoxes
|
||||
import ClientGUIMenus
|
||||
import ClientSearch
|
||||
import collections
|
||||
import HydrusConstants as HC
|
||||
|
@ -536,8 +537,6 @@ class AutoCompleteDropdownTags( AutoCompleteDropdown ):
|
|||
self._tag_repo_button = ClientGUICommon.BetterButton( self._dropdown_window, tag_service.GetName(), self.TagButtonHit )
|
||||
self._tag_repo_button.SetMinSize( ( 20, -1 ) )
|
||||
|
||||
self.Bind( wx.EVT_MENU, self.EventMenu )
|
||||
|
||||
|
||||
def _ChangeFileService( self, file_service_key ):
|
||||
|
||||
|
@ -599,31 +598,6 @@ class AutoCompleteDropdownTags( AutoCompleteDropdown ):
|
|||
|
||||
|
||||
|
||||
def EventMenu( self, event ):
|
||||
|
||||
action = ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetAction( event.GetId() )
|
||||
|
||||
if action is not None:
|
||||
|
||||
( command, data ) = action
|
||||
|
||||
if command == 'change_file_service':
|
||||
|
||||
self._ChangeFileService( data )
|
||||
|
||||
elif command == 'change_tag_service':
|
||||
|
||||
self._ChangeTagService( data )
|
||||
|
||||
else:
|
||||
|
||||
event.Skip()
|
||||
|
||||
return # this is about select_up and select_down
|
||||
|
||||
|
||||
|
||||
|
||||
def FileButtonHit( self ):
|
||||
|
||||
services_manager = HydrusGlobals.client_controller.GetServicesManager()
|
||||
|
@ -640,7 +614,7 @@ class AutoCompleteDropdownTags( AutoCompleteDropdown ):
|
|||
|
||||
for service in services:
|
||||
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'change_file_service', service.GetServiceKey() ), service.GetName() )
|
||||
ClientGUIMenus.AppendMenuItem( self, menu, service.GetName(), 'Change the current file domain to ' + service.GetName() + '.', self._ChangeFileService, service.GetServiceKey() )
|
||||
|
||||
|
||||
HydrusGlobals.client_controller.PopupMenu( self._file_repo_button, menu )
|
||||
|
@ -670,7 +644,7 @@ class AutoCompleteDropdownTags( AutoCompleteDropdown ):
|
|||
|
||||
for service in services:
|
||||
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'change_tag_service', service.GetServiceKey() ), service.GetName() )
|
||||
ClientGUIMenus.AppendMenuItem( self, menu, service.GetName(), 'Change the current tag domain to ' + service.GetName() + '.', self._ChangeTagService, service.GetServiceKey() )
|
||||
|
||||
|
||||
HydrusGlobals.client_controller.PopupMenu( self._tag_repo_button, menu )
|
||||
|
|
|
@ -213,6 +213,8 @@ def ShouldHaveAnimationBar( media ):
|
|||
|
||||
is_native_video = media.GetMime() in HC.NATIVE_VIDEO
|
||||
|
||||
has_more_than_one_frame = media.GetNumFrames() > 1
|
||||
|
||||
return is_animated_gif or is_animated_flash or is_native_video
|
||||
|
||||
class Animation( wx.Window ):
|
||||
|
@ -681,6 +683,11 @@ class AnimationBar( wx.Window ):
|
|||
|
||||
def _GetXFromFrameIndex( self, index, width_offset = 0 ):
|
||||
|
||||
if self._num_frames < 2:
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
( my_width, my_height ) = self._canvas_bmp.GetSize()
|
||||
|
||||
return int( float( my_width - width_offset ) * float( index ) / float( self._num_frames - 1 ) )
|
||||
|
@ -1208,7 +1215,10 @@ class Canvas( wx.Window ):
|
|||
|
||||
|
||||
|
||||
def _GetIndexString( self ): return ''
|
||||
def _GetIndexString( self ):
|
||||
|
||||
return ''
|
||||
|
||||
|
||||
def _GetMediaContainerSizeAndPosition( self ):
|
||||
|
||||
|
@ -1778,7 +1788,7 @@ class CanvasPanel( Canvas ):
|
|||
|
||||
for line in self._current_media.GetPrettyInfoLines():
|
||||
|
||||
menu.Append( CC.ID_NULL, line )
|
||||
ClientGUIMenus.AppendMenuLabel( menu, line, line )
|
||||
|
||||
|
||||
#
|
||||
|
@ -1789,60 +1799,67 @@ class CanvasPanel( Canvas ):
|
|||
|
||||
manage_menu = wx.Menu()
|
||||
|
||||
manage_menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'manage_tags' ), 'tags' )
|
||||
manage_menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'manage_ratings' ), 'ratings' )
|
||||
ClientGUIMenus.AppendMenuItem( self, manage_menu, 'tags', 'Manage tags for the selected files.', self._ManageTags )
|
||||
ClientGUIMenus.AppendMenuItem( self, manage_menu, 'ratings', 'Manage ratings for the selected files.', self._ManageRatings )
|
||||
|
||||
menu.AppendMenu( CC.ID_NULL, 'manage', manage_menu )
|
||||
ClientGUIMenus.AppendMenu( menu, manage_menu, 'manage' )
|
||||
|
||||
else:
|
||||
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'manage_tags' ), 'manage tags' )
|
||||
ClientGUIMenus.AppendMenuItem( self, menu, 'manage tags', 'Manage tags for the selected files.', self._ManageTags )
|
||||
|
||||
|
||||
ClientGUIMenus.AppendSeparator( menu )
|
||||
|
||||
if self._current_media.HasInbox(): menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'archive' ), '&archive' )
|
||||
if self._current_media.HasArchive(): menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'inbox' ), 'return to &inbox' )
|
||||
if self._current_media.HasInbox():
|
||||
|
||||
ClientGUIMenus.AppendMenuItem( self, menu, 'archive', 'Archive the selected files.', self._Archive )
|
||||
|
||||
|
||||
if self._current_media.HasArchive():
|
||||
|
||||
ClientGUIMenus.AppendMenuItem( self, menu, 'inbox', 'Send the selected files back to the inbox.', self._Inbox )
|
||||
|
||||
|
||||
if CC.LOCAL_FILE_SERVICE_KEY in locations_manager.GetCurrent():
|
||||
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'delete', CC.LOCAL_FILE_SERVICE_KEY ), '&delete' )
|
||||
ClientGUIMenus.AppendMenuItem( self, menu, 'delete', 'Delete the selected files.', self._Delete, CC.LOCAL_FILE_SERVICE_KEY )
|
||||
|
||||
elif CC.TRASH_SERVICE_KEY in locations_manager.GetCurrent():
|
||||
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'delete', CC.TRASH_SERVICE_KEY ), '&delete from trash now' )
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'undelete' ), '&undelete' )
|
||||
ClientGUIMenus.AppendMenuItem( self, menu, 'delete completely', 'Physically delete the selected files from disk.', self._Delete, CC.TRASH_SERVICE_KEY )
|
||||
ClientGUIMenus.AppendMenuItem( self, menu, 'undelete', 'Take the selected files out of the trash.', self._Undelete )
|
||||
|
||||
|
||||
ClientGUIMenus.AppendSeparator( menu )
|
||||
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'open_externally' ), '&open externally' )
|
||||
ClientGUIMenus.AppendMenuItem( self, menu, 'open externally', 'Open the file in your OS\'s default program.', self._OpenExternally )
|
||||
|
||||
share_menu = wx.Menu()
|
||||
|
||||
copy_menu = wx.Menu()
|
||||
|
||||
copy_menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'copy_files' ), 'file' )
|
||||
ClientGUIMenus.AppendMenuItem( self, copy_menu, 'file', 'Copy the file to your clipboard.', self._CopyFileToClipboard )
|
||||
|
||||
copy_hash_menu = wx.Menu()
|
||||
|
||||
copy_hash_menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'copy_hash', 'sha256' ) , 'sha256 (hydrus default)' )
|
||||
copy_hash_menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'copy_hash', 'md5' ) , 'md5' )
|
||||
copy_hash_menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'copy_hash', 'sha1' ) , 'sha1' )
|
||||
copy_hash_menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'copy_hash', 'sha512' ) , 'sha512' )
|
||||
ClientGUIMenus.AppendMenuItem( self, copy_hash_menu, 'sha256 (hydrus default)', 'Open the file\'s SHA256 hash.', self._CopyHashToClipboard, 'sha256' )
|
||||
ClientGUIMenus.AppendMenuItem( self, copy_hash_menu, 'md5', 'Open the file\'s MD5 hash.', self._CopyHashToClipboard, 'md5' )
|
||||
ClientGUIMenus.AppendMenuItem( self, copy_hash_menu, 'sha1', 'Open the file\'s SHA1 hash.', self._CopyHashToClipboard, 'sha1' )
|
||||
ClientGUIMenus.AppendMenuItem( self, copy_hash_menu, 'sha512', 'Open the file\'s SHA512 hash.', self._CopyHashToClipboard, 'sha512' )
|
||||
|
||||
copy_menu.AppendMenu( CC.ID_NULL, 'hash', copy_hash_menu )
|
||||
ClientGUIMenus.AppendMenu( copy_menu, copy_hash_menu, 'hash' )
|
||||
|
||||
if self._current_media.GetMime() in HC.IMAGES and self._current_media.GetDuration() is None:
|
||||
|
||||
copy_menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'copy_bmp' ), 'image' )
|
||||
ClientGUIMenus.AppendMenuItem( self, copy_menu, 'image', 'Copy the file to your clipboard as a bmp.', self._CopyBMPToClipboard )
|
||||
|
||||
|
||||
copy_menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'copy_path' ), 'path' )
|
||||
ClientGUIMenus.AppendMenuItem( self, copy_menu, 'path', 'Copy the file\'s path to your clipboard.', self._CopyPathToClipboard )
|
||||
|
||||
share_menu.AppendMenu( CC.ID_NULL, 'copy', copy_menu )
|
||||
ClientGUIMenus.AppendMenu( share_menu, copy_menu, 'copy' )
|
||||
|
||||
menu.AppendMenu( CC.ID_NULL, 'share', share_menu )
|
||||
ClientGUIMenus.AppendMenu( menu, share_menu, 'share' )
|
||||
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
|
@ -2086,141 +2103,6 @@ class CanvasWithDetails( Canvas ):
|
|||
return info_string
|
||||
|
||||
|
||||
class CanvasFilterDuplicates( CanvasWithDetails ):
|
||||
|
||||
def __init__( self, parent, file_service_key ):
|
||||
|
||||
CanvasWithDetails.__init__( self, parent )
|
||||
|
||||
self._file_service_key = file_service_key
|
||||
|
||||
self._media_list = ClientMedia.ListeningMediaList( self._file_service_key, [] )
|
||||
|
||||
self.Bind( wx.EVT_MOUSEWHEEL, self.EventMouseWheel )
|
||||
self.Bind( wx.EVT_CHAR_HOOK, self.EventCharHook )
|
||||
|
||||
# make a hover here
|
||||
# hover has
|
||||
# 'this is better'
|
||||
# 'the same'
|
||||
# 'alternates'
|
||||
# 'complicated' (opens a quick dialog or something that lets you choose all this stuff in checkboxes
|
||||
# 'show another'
|
||||
# cog icon to control
|
||||
# file delete on better
|
||||
# rating merging on better (d NO) (these are mutually exclusive, so add a radio menu type or whatever)
|
||||
# rating moving on better (d YES)
|
||||
# rating merging on same (d YES)
|
||||
# tag merging on better (d NO) (these are mutually exclusive, so add a radio menu type or whatever)
|
||||
# tag moving on better (d YES)
|
||||
# tag merging on same (d YES)
|
||||
|
||||
# add support for 'f' to borderless
|
||||
# add support for F4 and other general shortcuts so people can do edits before processing
|
||||
|
||||
wx.CallAfter( self._ShowNewPair ) # don't set this until we have a size > (20, 20)!
|
||||
|
||||
HydrusGlobals.client_controller.sub( self, 'ProcessContentUpdates', 'content_updates_gui' )
|
||||
|
||||
|
||||
def _Close( self ):
|
||||
|
||||
self._closing = True
|
||||
|
||||
self.GetParent().Close()
|
||||
|
||||
|
||||
def _CurrentMediaIsBetter( self ):
|
||||
|
||||
pass
|
||||
|
||||
self._ShowNewPair()
|
||||
|
||||
|
||||
def _MediaAreAlternates( self ):
|
||||
|
||||
pass
|
||||
|
||||
self._ShowNewPair()
|
||||
|
||||
|
||||
def _MediaAreTheSame( self ):
|
||||
|
||||
pass
|
||||
|
||||
self._ShowNewPair()
|
||||
|
||||
|
||||
def _ShowNewPair( self ):
|
||||
|
||||
result = HydrusGlobals.client_controller.Read( 'duplicate_pair', self._file_service_key, HC.DUPLICATE_UNKNOWN )
|
||||
|
||||
if result is None:
|
||||
|
||||
self._Close()
|
||||
|
||||
else:
|
||||
|
||||
media_results = result
|
||||
|
||||
self._media_list = ClientMedia.ListeningMediaList( self._file_service_key, media_results )
|
||||
|
||||
self.SetMedia( self._media_list.GetFirst() )
|
||||
|
||||
|
||||
|
||||
def _SwitchMedia( self ):
|
||||
|
||||
self.SetMedia( self._media_list.GetNext( self._current_media ) )
|
||||
|
||||
|
||||
def EventCharHook( self, event ):
|
||||
|
||||
( modifier, key ) = ClientData.GetShortcutFromEvent( event )
|
||||
|
||||
if key in ( wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER, wx.WXK_ESCAPE ):
|
||||
|
||||
self._Close()
|
||||
|
||||
|
||||
|
||||
def EventClose( self, event ):
|
||||
|
||||
self._Close()
|
||||
|
||||
|
||||
def EventMouseWheel( self, event ):
|
||||
|
||||
if self._HydrusShouldNotProcessInput():
|
||||
|
||||
event.Skip()
|
||||
|
||||
else:
|
||||
|
||||
self._SwitchMedia()
|
||||
|
||||
|
||||
|
||||
def ProcessContentUpdates( self, service_keys_to_content_updates ):
|
||||
|
||||
def catch_up():
|
||||
|
||||
# ugly, but it will do for now
|
||||
|
||||
if len( self._media_list ) < 2:
|
||||
|
||||
self._ShowNewPair()
|
||||
|
||||
else:
|
||||
|
||||
self._SetDirty()
|
||||
|
||||
|
||||
|
||||
|
||||
wx.CallLater( 100, catch_up )
|
||||
|
||||
|
||||
class CanvasFrame( ClientGUITopLevelWindows.FrameThatResizes ):
|
||||
|
||||
def __init__( self, parent ):
|
||||
|
@ -2284,7 +2166,7 @@ class CanvasWithHovers( CanvasWithDetails ):
|
|||
|
||||
CanvasWithDetails.__init__( self, parent )
|
||||
|
||||
self._hover_commands = ClientGUIHoverFrames.FullscreenHoverFrameCommands( self, self._canvas_key )
|
||||
self._hover_commands = self._GenerateHoverTopFrame()
|
||||
self._hover_tags = ClientGUIHoverFrames.FullscreenHoverFrameTags( self, self._canvas_key )
|
||||
|
||||
ratings_services = HydrusGlobals.client_controller.GetServicesManager().GetServices( ( HC.RATINGS_SERVICES ) )
|
||||
|
@ -2295,6 +2177,190 @@ class CanvasWithHovers( CanvasWithDetails ):
|
|||
|
||||
|
||||
|
||||
def _GenerateHoverTopFrame( self ):
|
||||
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class CanvasFilterDuplicates( CanvasWithHovers ):
|
||||
|
||||
def __init__( self, parent, file_service_key ):
|
||||
|
||||
CanvasWithHovers.__init__( self, parent )
|
||||
|
||||
self._file_service_key = file_service_key
|
||||
|
||||
self._media_list = ClientMedia.ListeningMediaList( self._file_service_key, [] )
|
||||
|
||||
self._hover_commands.AddCommand( 'this is better', self._CurrentMediaIsBetter )
|
||||
self._hover_commands.AddCommand( 'exact duplicates', self._MediaAreTheSame )
|
||||
self._hover_commands.AddCommand( 'alternates', self._MediaAreAlternates )
|
||||
self._hover_commands.AddCommand( 'custom action', self._DoCustomAction )
|
||||
|
||||
self.Bind( wx.EVT_MOUSEWHEEL, self.EventMouseWheel )
|
||||
self.Bind( wx.EVT_CHAR_HOOK, self.EventCharHook )
|
||||
|
||||
# add support for 'f' to borderless
|
||||
# add support for F4 and other general shortcuts so people can do edits before processing
|
||||
|
||||
wx.CallAfter( self._ShowNewPair ) # don't set this until we have a size > (20, 20)!
|
||||
|
||||
HydrusGlobals.client_controller.sub( self, 'ProcessContentUpdates', 'content_updates_gui' )
|
||||
HydrusGlobals.client_controller.sub( self, 'SwitchMedia', 'canvas_show_next' )
|
||||
HydrusGlobals.client_controller.sub( self, 'SwitchMedia', 'canvas_show_previous' )
|
||||
HydrusGlobals.client_controller.sub( self, 'ShowNewPair', 'canvas_show_new_pair' )
|
||||
|
||||
|
||||
def _Close( self ):
|
||||
|
||||
self._closing = True
|
||||
|
||||
self.GetParent().Close()
|
||||
|
||||
|
||||
def _CurrentMediaIsBetter( self ):
|
||||
|
||||
pass
|
||||
|
||||
self._ShowNewPair()
|
||||
|
||||
|
||||
def _DoCustomAction( self ):
|
||||
|
||||
pass
|
||||
|
||||
# launch the dialog to choose exactly what happens
|
||||
# if OK on that:
|
||||
self._ShowNewPair()
|
||||
|
||||
|
||||
def _GenerateHoverTopFrame( self ):
|
||||
|
||||
return ClientGUIHoverFrames.FullscreenHoverFrameTopDuplicatesFilter( self, self._canvas_key )
|
||||
|
||||
|
||||
def _GetIndexString( self ):
|
||||
|
||||
if self._current_media is None:
|
||||
|
||||
return '-'
|
||||
|
||||
else:
|
||||
|
||||
if self._media_list.GetFirst() == self._current_media:
|
||||
|
||||
return 'A'
|
||||
|
||||
else:
|
||||
|
||||
return 'B'
|
||||
|
||||
|
||||
|
||||
|
||||
def _MediaAreAlternates( self ):
|
||||
|
||||
pass
|
||||
|
||||
self._ShowNewPair()
|
||||
|
||||
|
||||
def _MediaAreTheSame( self ):
|
||||
|
||||
pass
|
||||
|
||||
self._ShowNewPair()
|
||||
|
||||
|
||||
def _ShowNewPair( self ):
|
||||
|
||||
result = HydrusGlobals.client_controller.Read( 'duplicate_pair', self._file_service_key, HC.DUPLICATE_UNKNOWN )
|
||||
|
||||
if result is None:
|
||||
|
||||
self._Close()
|
||||
|
||||
else:
|
||||
|
||||
media_results = result
|
||||
|
||||
self._media_list = ClientMedia.ListeningMediaList( self._file_service_key, media_results )
|
||||
|
||||
self.SetMedia( self._media_list.GetFirst() )
|
||||
|
||||
|
||||
|
||||
def _SwitchMedia( self ):
|
||||
|
||||
if self._current_media is not None:
|
||||
|
||||
self.SetMedia( self._media_list.GetNext( self._current_media ) )
|
||||
|
||||
|
||||
|
||||
def EventCharHook( self, event ):
|
||||
|
||||
( modifier, key ) = ClientData.GetShortcutFromEvent( event )
|
||||
|
||||
if key in ( wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER, wx.WXK_ESCAPE ):
|
||||
|
||||
self._Close()
|
||||
|
||||
|
||||
|
||||
def EventClose( self, event ):
|
||||
|
||||
self._Close()
|
||||
|
||||
|
||||
def EventMouseWheel( self, event ):
|
||||
|
||||
if self._HydrusShouldNotProcessInput():
|
||||
|
||||
event.Skip()
|
||||
|
||||
else:
|
||||
|
||||
self._SwitchMedia()
|
||||
|
||||
|
||||
|
||||
def ProcessContentUpdates( self, service_keys_to_content_updates ):
|
||||
|
||||
def catch_up():
|
||||
|
||||
# ugly, but it will do for now
|
||||
|
||||
if len( self._media_list ) < 2:
|
||||
|
||||
self._ShowNewPair()
|
||||
|
||||
else:
|
||||
|
||||
self._SetDirty()
|
||||
|
||||
|
||||
|
||||
|
||||
wx.CallLater( 100, catch_up )
|
||||
|
||||
|
||||
def ShowNewPair( self, canvas_key ):
|
||||
|
||||
if canvas_key == self._canvas_key:
|
||||
|
||||
self._ShowNewPair()
|
||||
|
||||
|
||||
|
||||
def SwitchMedia( self, canvas_key ):
|
||||
|
||||
if canvas_key == self._canvas_key:
|
||||
|
||||
self._SwitchMedia()
|
||||
|
||||
|
||||
|
||||
class CanvasMediaList( ClientMedia.ListeningMediaList, CanvasWithHovers ):
|
||||
|
||||
def __init__( self, parent, page_key, media_results ):
|
||||
|
@ -2685,9 +2751,6 @@ class CanvasMediaListFilterInbox( CanvasMediaList ):
|
|||
HydrusGlobals.client_controller.sub( self, 'Undelete', 'canvas_undelete' )
|
||||
HydrusGlobals.client_controller.sub( self, 'Back', 'canvas_show_previous' )
|
||||
|
||||
self._hover_commands.SetNavigable( False )
|
||||
self._hover_commands.SetAlwaysArchive( True )
|
||||
|
||||
wx.CallAfter( self.SetMedia, self._GetFirst() ) # don't set this until we have a size > (20, 20)!
|
||||
|
||||
|
||||
|
@ -2782,6 +2845,11 @@ class CanvasMediaListFilterInbox( CanvasMediaList ):
|
|||
else: self._ShowNext()
|
||||
|
||||
|
||||
def _GenerateHoverTopFrame( self ):
|
||||
|
||||
return ClientGUIHoverFrames.FullscreenHoverFrameTopInboxFilter( self, self._canvas_key )
|
||||
|
||||
|
||||
def _Keep( self ):
|
||||
|
||||
self._kept.add( self._current_media )
|
||||
|
@ -2968,7 +3036,10 @@ class CanvasMediaListNavigable( CanvasMediaList ):
|
|||
HydrusGlobals.client_controller.sub( self, 'ShowPrevious', 'canvas_show_previous' )
|
||||
HydrusGlobals.client_controller.sub( self, 'Undelete', 'canvas_undelete' )
|
||||
|
||||
self._hover_commands.SetNavigable( True )
|
||||
|
||||
def _GenerateHoverTopFrame( self ):
|
||||
|
||||
return ClientGUIHoverFrames.FullscreenHoverFrameTopNavigableList( self, self._canvas_key )
|
||||
|
||||
|
||||
def Archive( self, canvas_key ):
|
||||
|
@ -3434,7 +3505,7 @@ class CanvasMediaListCustomFilter( CanvasMediaListNavigable ):
|
|||
|
||||
wx.CallAfter( self.SetMedia, self._GetFirst() ) # don't set this until we have a size > (20, 20)!
|
||||
|
||||
self._hover_commands.AddCommand( 'edit shortcuts', self.EventShortcuts )
|
||||
self._hover_commands.AddCommand( 'edit shortcuts', self.EditShortcuts )
|
||||
|
||||
HydrusGlobals.client_controller.sub( self, 'AddMediaResults', 'add_media_results' )
|
||||
|
||||
|
@ -3453,11 +3524,14 @@ class CanvasMediaListCustomFilter( CanvasMediaListNavigable ):
|
|||
HydrusGlobals.client_controller.Write( 'content_updates', { CC.COMBINED_LOCAL_FILE_SERVICE_KEY : [ HydrusData.ContentUpdate( HC.CONTENT_TYPE_FILES, HC.CONTENT_UPDATE_INBOX, ( self._current_media.GetHash(), ) ) ] } )
|
||||
|
||||
|
||||
def EventShortcuts( self, event ):
|
||||
def EditShortcuts( self ):
|
||||
|
||||
with ClientGUIDialogs.DialogShortcuts( self ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_OK: self._shortcuts = dlg.GetShortcuts()
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
|
||||
self._shortcuts = dlg.GetShortcuts()
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -3491,6 +3565,7 @@ class CanvasMediaListCustomFilter( CanvasMediaListNavigable ):
|
|||
elif data == 'pan_left': self._DoManualPan( -1, 0 )
|
||||
elif data == 'pan_right': self._DoManualPan( 1, 0 )
|
||||
|
||||
elif data == 'remove': self._Remove()
|
||||
elif data == 'first': self._ShowFirst()
|
||||
elif data == 'last': self._ShowLast()
|
||||
elif data == 'previous': self._ShowPrevious()
|
||||
|
@ -3518,7 +3593,10 @@ class CanvasMediaListCustomFilter( CanvasMediaListNavigable ):
|
|||
|
||||
tags = [ tag ]
|
||||
|
||||
if tag in current: content_update_action = HC.CONTENT_UPDATE_DELETE
|
||||
if tag in current:
|
||||
|
||||
content_update_action = HC.CONTENT_UPDATE_DELETE
|
||||
|
||||
else:
|
||||
|
||||
content_update_action = HC.CONTENT_UPDATE_ADD
|
||||
|
|
|
@ -165,7 +165,7 @@ class BetterButton( wx.Button ):
|
|||
|
||||
def __init__( self, parent, label, func, *args, **kwargs ):
|
||||
|
||||
wx.Button.__init__( self, parent, label = label )
|
||||
wx.Button.__init__( self, parent, label = label, style = wx.BU_EXACTFIT )
|
||||
|
||||
self._func = func
|
||||
self._args = args
|
||||
|
|
|
@ -1528,7 +1528,7 @@ class DialogInputLocalBooruShare( Dialog ):
|
|||
external_port = self._service.GetPort()
|
||||
|
||||
|
||||
url = 'http://' + external_ip + ':' + str( external_port ) + '/gallery?share_key=' + self._share_key.encode( 'hex' )
|
||||
url = 'http://' + external_ip + ':' + HydrusData.ToUnicode( external_port ) + '/gallery?share_key=' + self._share_key.encode( 'hex' )
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'clipboard', 'text', url )
|
||||
|
||||
|
@ -4144,7 +4144,11 @@ class DialogSetupExport( Dialog ):
|
|||
|
||||
self._directory_picker.SetPath( export_path )
|
||||
|
||||
self._pattern.SetValue( '{hash}' )
|
||||
new_options = HydrusGlobals.client_controller.GetNewOptions()
|
||||
|
||||
phrase = new_options.GetString( 'export_phrase' )
|
||||
|
||||
self._pattern.SetValue( phrase )
|
||||
|
||||
#
|
||||
|
||||
|
@ -4258,6 +4262,10 @@ class DialogSetupExport( Dialog ):
|
|||
|
||||
pattern = self._pattern.GetValue()
|
||||
|
||||
new_options = HydrusGlobals.client_controller.GetNewOptions()
|
||||
|
||||
new_options.SetString( 'export_phrase', pattern )
|
||||
|
||||
terms = ClientExporting.ParseExportPhrase( pattern )
|
||||
|
||||
client_files_manager = HydrusGlobals.client_controller.GetClientFilesManager()
|
||||
|
@ -4370,10 +4378,23 @@ class DialogSetupExport( Dialog ):
|
|||
|
||||
HydrusPaths.LaunchDirectory( directory )
|
||||
|
||||
except: wx.MessageBox( 'Could not open that location!' )
|
||||
except:
|
||||
|
||||
wx.MessageBox( 'Could not open that location!' )
|
||||
|
||||
|
||||
|
||||
|
||||
def EventRecalcPaths( self, event ): self._RecalcPaths()
|
||||
def EventRecalcPaths( self, event ):
|
||||
|
||||
pattern = self._pattern.GetValue()
|
||||
|
||||
new_options = HydrusGlobals.client_controller.GetNewOptions()
|
||||
|
||||
new_options.SetString( 'export_phrase', pattern )
|
||||
|
||||
self._RecalcPaths()
|
||||
|
||||
|
||||
def EventSelectPath( self, event ):
|
||||
|
||||
|
|
|
@ -271,7 +271,7 @@ class DialogManageBoorus( ClientGUIDialogs.Dialog ):
|
|||
|
||||
except HydrusExceptions.NameException as e:
|
||||
|
||||
wx.MessageBox( str( e ) )
|
||||
wx.MessageBox( HydrusData.ToUnicode( e ) )
|
||||
|
||||
self.EventAdd( event )
|
||||
|
||||
|
@ -1246,12 +1246,15 @@ class DialogManageExportFolders( ClientGUIDialogs.Dialog ):
|
|||
|
||||
def _AddFolder( self ):
|
||||
|
||||
new_options = HydrusGlobals.client_controller.GetNewOptions()
|
||||
|
||||
phrase = new_options.GetString( 'export_phrase' )
|
||||
|
||||
name = 'export folder'
|
||||
path = ''
|
||||
export_type = HC.EXPORT_FOLDER_TYPE_REGULAR
|
||||
file_search_context = ClientSearch.FileSearchContext( file_service_key = CC.LOCAL_FILE_SERVICE_KEY )
|
||||
period = 15 * 60
|
||||
phrase = '{hash}'
|
||||
|
||||
export_folder = ClientExporting.ExportFolder( name, path, export_type = export_type, file_search_context = file_search_context, period = period, phrase = phrase )
|
||||
|
||||
|
@ -1653,7 +1656,7 @@ class DialogManageImageboards( ClientGUIDialogs.Dialog ):
|
|||
|
||||
except HydrusExceptions.NameException as e:
|
||||
|
||||
wx.MessageBox( str( e ) )
|
||||
wx.MessageBox( HydrusData.ToUnicode( e ) )
|
||||
|
||||
self.EventAdd( event )
|
||||
|
||||
|
|
|
@ -61,12 +61,6 @@ class FullscreenHoverFrame( wx.Frame ):
|
|||
|
||||
self.SetPosition( my_ideal_position )
|
||||
|
||||
|
||||
|
||||
def GiveParentFocus( self ):
|
||||
|
||||
self.GetParent().SetFocus()
|
||||
|
||||
|
||||
def SetDisplayMedia( self, canvas_key, media ):
|
||||
|
||||
|
@ -173,101 +167,28 @@ class FullscreenHoverFrame( wx.Frame ):
|
|||
raise
|
||||
|
||||
|
||||
|
||||
class FullscreenHoverFrameCommands( FullscreenHoverFrame ):
|
||||
|
||||
class FullscreenHoverFrameTop( FullscreenHoverFrame ):
|
||||
|
||||
def __init__( self, parent, canvas_key ):
|
||||
|
||||
FullscreenHoverFrame.__init__( self, parent, canvas_key )
|
||||
|
||||
self._always_archive = False
|
||||
self._current_zoom = 1.0
|
||||
self._current_index_string = ''
|
||||
|
||||
vbox = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
self._first_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.first )
|
||||
self._first_button.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_show_first', self._canvas_key ) )
|
||||
self._first_button.SetToolTipString( 'first' )
|
||||
|
||||
self._previous_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.previous )
|
||||
self._previous_button.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_show_previous', self._canvas_key ) )
|
||||
self._previous_button.SetToolTipString( 'previous' )
|
||||
|
||||
self._index_text = wx.StaticText( self, label = 'index' )
|
||||
|
||||
self._next_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.next )
|
||||
self._next_button.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_show_next', self._canvas_key ) )
|
||||
self._next_button.SetToolTipString( 'next' )
|
||||
|
||||
self._last_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.last )
|
||||
self._last_button.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_show_last', self._canvas_key ) )
|
||||
self._last_button.SetToolTipString( 'last' )
|
||||
|
||||
self._archive_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.archive )
|
||||
self._archive_button.Bind( wx.EVT_BUTTON, self.EventArchiveButton )
|
||||
|
||||
self._trash_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.delete )
|
||||
self._trash_button.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_delete', self._canvas_key ) )
|
||||
self._trash_button.SetToolTipString( 'send to trash' )
|
||||
|
||||
self._delete_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.trash_delete )
|
||||
self._delete_button.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_delete', self._canvas_key ) )
|
||||
self._delete_button.SetToolTipString( 'delete completely' )
|
||||
|
||||
self._undelete_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.undelete )
|
||||
self._undelete_button.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_undelete', self._canvas_key ) )
|
||||
self._undelete_button.SetToolTipString( 'undelete' )
|
||||
|
||||
self._zoom_text = wx.StaticText( self, label = 'zoom' )
|
||||
|
||||
zoom_in = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.zoom_in )
|
||||
zoom_in.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_zoom_in', self._canvas_key ) )
|
||||
zoom_in.SetToolTipString( 'zoom in' )
|
||||
|
||||
zoom_out = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.zoom_out )
|
||||
zoom_out.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_zoom_out', self._canvas_key ) )
|
||||
zoom_out.SetToolTipString( 'zoom out' )
|
||||
|
||||
zoom_switch = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.zoom_switch )
|
||||
zoom_switch.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_zoom_switch', self._canvas_key ) )
|
||||
zoom_switch.SetToolTipString( 'zoom switch' )
|
||||
|
||||
fullscreen_switch = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.fullscreen_switch )
|
||||
fullscreen_switch.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_fullscreen_switch', self._canvas_key ) )
|
||||
fullscreen_switch.SetToolTipString( 'fullscreen switch' )
|
||||
|
||||
open_externally = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.open_externally )
|
||||
open_externally.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_open_externally', self._canvas_key ) )
|
||||
open_externally.SetToolTipString( 'open externally' )
|
||||
|
||||
close = wx.Button( self, label = 'X', style = wx.BU_EXACTFIT )
|
||||
close.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_close', self._canvas_key ) )
|
||||
close.SetToolTipString( 'close' )
|
||||
|
||||
self._top_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
||||
self._title_text = wx.StaticText( self, label = 'title' )
|
||||
self._info_text = wx.StaticText( self, label = 'info' )
|
||||
self._button_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
self._top_hbox.AddF( self._first_button, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( self._previous_button, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( self._index_text, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( self._next_button, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( self._last_button, CC.FLAGS_VCENTER )
|
||||
self._PopulateLeftButtons()
|
||||
self._top_hbox.AddF( ( 20, 20 ), CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
self._top_hbox.AddF( self._archive_button, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( self._trash_button, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( self._delete_button, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( self._undelete_button, CC.FLAGS_VCENTER )
|
||||
self._PopulateCenterButtons()
|
||||
self._top_hbox.AddF( ( 20, 20 ), CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
self._top_hbox.AddF( self._zoom_text, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( zoom_in, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( zoom_out, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( zoom_switch, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( fullscreen_switch, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( open_externally, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( close, CC.FLAGS_VCENTER )
|
||||
self._PopulateRightButtons()
|
||||
|
||||
vbox = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
vbox.AddF( self._top_hbox, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
vbox.AddF( self._title_text, CC.FLAGS_CENTER )
|
||||
|
@ -276,13 +197,25 @@ class FullscreenHoverFrameCommands( FullscreenHoverFrame ):
|
|||
|
||||
self.SetSizer( vbox )
|
||||
|
||||
HydrusGlobals.client_controller.sub( self, 'ProcessContentUpdates', 'content_updates_gui' )
|
||||
HydrusGlobals.client_controller.sub( self, 'SetCurrentZoom', 'canvas_new_zoom' )
|
||||
HydrusGlobals.client_controller.sub( self, 'SetIndexString', 'canvas_new_index_string' )
|
||||
HydrusGlobals.client_controller.sub( self, 'ProcessContentUpdates', 'content_updates_gui' )
|
||||
|
||||
self.Bind( wx.EVT_MOUSEWHEEL, self.EventMouseWheel )
|
||||
|
||||
|
||||
def _Archive( self ):
|
||||
|
||||
if self._current_media.HasInbox():
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'canvas_archive', self._canvas_key )
|
||||
|
||||
else:
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'canvas_inbox', self._canvas_key )
|
||||
|
||||
|
||||
|
||||
def _GetIdealSizeAndPosition( self ):
|
||||
|
||||
parent = self.GetParent()
|
||||
|
@ -301,20 +234,90 @@ class FullscreenHoverFrameCommands( FullscreenHoverFrame ):
|
|||
return ( should_resize, ideal_size, ideal_position )
|
||||
|
||||
|
||||
def _PopulateCenterButtons( self ):
|
||||
|
||||
self._archive_button = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.archive, self._Archive )
|
||||
|
||||
self._trash_button = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.delete, HydrusGlobals.client_controller.pub, 'canvas_delete', self._canvas_key )
|
||||
self._trash_button.SetToolTipString( 'send to trash' )
|
||||
|
||||
self._delete_button = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.trash_delete, HydrusGlobals.client_controller.pub, 'canvas_delete', self._canvas_key )
|
||||
self._delete_button.SetToolTipString( 'delete completely' )
|
||||
|
||||
self._undelete_button = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.undelete, HydrusGlobals.client_controller.pub, 'canvas_undelete', self._canvas_key )
|
||||
self._undelete_button.SetToolTipString( 'undelete' )
|
||||
|
||||
self._top_hbox.AddF( self._archive_button, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( self._trash_button, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( self._delete_button, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( self._undelete_button, CC.FLAGS_VCENTER )
|
||||
|
||||
|
||||
def _PopulateLeftButtons( self ):
|
||||
|
||||
self._previous_button = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.previous, HydrusGlobals.client_controller.pub, 'canvas_show_previous', self._canvas_key )
|
||||
self._previous_button.SetToolTipString( 'previous' )
|
||||
|
||||
self._index_text = wx.StaticText( self, label = 'index' )
|
||||
|
||||
self._next_button = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.next, HydrusGlobals.client_controller.pub, 'canvas_show_next', self._canvas_key )
|
||||
self._next_button.SetToolTipString( 'next' )
|
||||
|
||||
self._top_hbox.AddF( self._previous_button, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( self._index_text, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( self._next_button, CC.FLAGS_VCENTER )
|
||||
|
||||
|
||||
def _PopulateRightButtons( self ):
|
||||
|
||||
self._zoom_text = wx.StaticText( self, label = 'zoom' )
|
||||
|
||||
zoom_in = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.zoom_in, HydrusGlobals.client_controller.pub, 'canvas_zoom_in', self._canvas_key )
|
||||
zoom_in.SetToolTipString( 'zoom in' )
|
||||
|
||||
zoom_out = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.zoom_out, HydrusGlobals.client_controller.pub, 'canvas_zoom_out', self._canvas_key )
|
||||
zoom_out.SetToolTipString( 'zoom out' )
|
||||
|
||||
zoom_switch = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.zoom_switch, HydrusGlobals.client_controller.pub, 'canvas_zoom_switch', self._canvas_key )
|
||||
zoom_switch.SetToolTipString( 'zoom switch' )
|
||||
|
||||
fullscreen_switch = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.fullscreen_switch, HydrusGlobals.client_controller.pub, 'canvas_fullscreen_switch', self._canvas_key )
|
||||
fullscreen_switch.SetToolTipString( 'fullscreen switch' )
|
||||
|
||||
open_externally = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.open_externally, HydrusGlobals.client_controller.pub, 'canvas_open_externally', self._canvas_key )
|
||||
open_externally.SetToolTipString( 'open externally' )
|
||||
|
||||
close = ClientGUICommon.BetterButton( self, 'X', HydrusGlobals.client_controller.pub, 'canvas_close', self._canvas_key )
|
||||
close.SetToolTipString( 'close' )
|
||||
|
||||
self._top_hbox.AddF( self._zoom_text, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( zoom_in, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( zoom_out, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( zoom_switch, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( fullscreen_switch, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( open_externally, CC.FLAGS_VCENTER )
|
||||
self._top_hbox.AddF( close, CC.FLAGS_VCENTER )
|
||||
|
||||
|
||||
def _ResetArchiveButton( self ):
|
||||
|
||||
if self._current_media.HasInbox():
|
||||
|
||||
self._archive_button.SetBitmapLabel( CC.GlobalBMPs.archive )
|
||||
self._archive_button.SetToolTipString( 'archive' )
|
||||
|
||||
else:
|
||||
|
||||
self._archive_button.SetBitmapLabel( CC.GlobalBMPs.to_inbox )
|
||||
self._archive_button.SetToolTipString( 'return to inbox' )
|
||||
|
||||
|
||||
|
||||
def _ResetButtons( self ):
|
||||
|
||||
if self._current_media is not None:
|
||||
|
||||
if self._always_archive or self._current_media.HasInbox():
|
||||
|
||||
self._archive_button.SetBitmapLabel( CC.GlobalBMPs.archive )
|
||||
self._archive_button.SetToolTipString( 'archive' )
|
||||
|
||||
else:
|
||||
|
||||
self._archive_button.SetBitmapLabel( CC.GlobalBMPs.to_inbox )
|
||||
self._archive_button.SetToolTipString( 'return to inbox' )
|
||||
|
||||
self._ResetArchiveButton()
|
||||
|
||||
current_locations = self._current_media.GetLocationsManager().GetCurrent()
|
||||
|
||||
|
@ -331,6 +334,10 @@ class FullscreenHoverFrameCommands( FullscreenHoverFrame ):
|
|||
self._undelete_button.Show()
|
||||
|
||||
|
||||
self.Fit()
|
||||
|
||||
self._SizeAndPosition()
|
||||
|
||||
|
||||
|
||||
def _ResetText( self ):
|
||||
|
@ -362,24 +369,11 @@ class FullscreenHoverFrameCommands( FullscreenHoverFrame ):
|
|||
|
||||
|
||||
|
||||
def AddCommand( self, label, callback ):
|
||||
def AddCommand( self, label, func ):
|
||||
|
||||
command = wx.Button( self, label = label, style = wx.BU_EXACTFIT )
|
||||
command.Bind( wx.EVT_BUTTON, callback )
|
||||
command_button = ClientGUICommon.BetterButton( self, label, func )
|
||||
|
||||
self._button_hbox.AddF( command, CC.FLAGS_VCENTER )
|
||||
|
||||
|
||||
def EventArchiveButton( self, event ):
|
||||
|
||||
if self._always_archive or self._current_media.HasInbox():
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'canvas_archive', self._canvas_key )
|
||||
|
||||
else:
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'canvas_inbox', self._canvas_key )
|
||||
|
||||
self._button_hbox.AddF( command_button, CC.FLAGS_VCENTER )
|
||||
|
||||
|
||||
def EventMouseWheel( self, event ):
|
||||
|
@ -410,20 +404,9 @@ class FullscreenHoverFrameCommands( FullscreenHoverFrame ):
|
|||
|
||||
self._ResetButtons()
|
||||
|
||||
self.Fit()
|
||||
|
||||
self._SizeAndPosition()
|
||||
|
||||
|
||||
|
||||
|
||||
def SetAlwaysArchive( self, value ):
|
||||
|
||||
self._always_archive = value
|
||||
|
||||
self._ResetButtons()
|
||||
|
||||
|
||||
def SetCurrentZoom( self, canvas_key, zoom ):
|
||||
|
||||
if canvas_key == self._canvas_key:
|
||||
|
@ -444,13 +427,9 @@ class FullscreenHoverFrameCommands( FullscreenHoverFrame ):
|
|||
|
||||
FullscreenHoverFrame.SetDisplayMedia( self, canvas_key, media )
|
||||
|
||||
self._ResetButtons()
|
||||
|
||||
self._ResetText()
|
||||
|
||||
self.Fit()
|
||||
|
||||
self._SizeAndPosition()
|
||||
self._ResetButtons()
|
||||
|
||||
|
||||
|
||||
|
@ -466,24 +445,82 @@ class FullscreenHoverFrameCommands( FullscreenHoverFrame ):
|
|||
|
||||
|
||||
|
||||
def SetNavigable( self, value ):
|
||||
class FullscreenHoverFrameTopDuplicatesFilter( FullscreenHoverFrameTop ):
|
||||
|
||||
def _PopulateCenterButtons( self ):
|
||||
|
||||
if value:
|
||||
|
||||
self._first_button.Show()
|
||||
self._last_button.Show()
|
||||
|
||||
self._previous_button.SetToolTipString( 'previous' )
|
||||
self._next_button.SetToolTipString( 'next' )
|
||||
|
||||
else:
|
||||
|
||||
self._first_button.Hide()
|
||||
self._last_button.Hide()
|
||||
|
||||
self._previous_button.SetToolTipString( 'back' )
|
||||
self._next_button.SetToolTipString( 'skip' )
|
||||
|
||||
# probably better to just launch a dialog with this stuff as proper panels, yeah
|
||||
# I'll be making those panels for the custom dialog anyway
|
||||
|
||||
# cog icon to control
|
||||
# file delete on better
|
||||
# rating merging on better (d NO) (these are mutually exclusive, so add a radio menu type or whatever)
|
||||
# rating moving on better (d YES)
|
||||
# rating merging on same (d YES)
|
||||
# tag merging on better (d NO) (these are mutually exclusive, so add a radio menu type or whatever)
|
||||
# tag moving on better (d YES)
|
||||
# tag merging on same (d YES)
|
||||
|
||||
menu_items = []
|
||||
|
||||
menu_items.append( ( 'normal', 'edit tag/ratings merge options and whether to delete bad files', 'help compute.', self._Archive ) )
|
||||
menu_items.append( ( 'normal', 'edit shortcuts', 'help compute.', self._Archive ) )
|
||||
|
||||
cog_button = ClientGUICommon.MenuBitmapButton( self, CC.GlobalBMPs.cog, menu_items )
|
||||
|
||||
self._top_hbox.AddF( cog_button, CC.FLAGS_SIZER_VCENTER )
|
||||
|
||||
FullscreenHoverFrameTop._PopulateCenterButtons( self )
|
||||
|
||||
|
||||
def _PopulateLeftButtons( self ):
|
||||
|
||||
FullscreenHoverFrameTop._PopulateLeftButtons( self )
|
||||
|
||||
self._last_button = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.last, HydrusGlobals.client_controller.pub, 'canvas_show_new_pair', self._canvas_key )
|
||||
self._last_button.SetToolTipString( 'show a different pair' )
|
||||
|
||||
self._top_hbox.AddF( self._last_button, CC.FLAGS_VCENTER )
|
||||
|
||||
|
||||
class FullscreenHoverFrameTopInboxFilter( FullscreenHoverFrameTop ):
|
||||
|
||||
def _Archive( self ):
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'canvas_archive', self._canvas_key )
|
||||
|
||||
|
||||
def _PopulateLeftButtons( self ):
|
||||
|
||||
FullscreenHoverFrameTop._PopulateLeftButtons( self )
|
||||
|
||||
self._previous_button.SetToolTipString( 'back' )
|
||||
self._next_button.SetToolTipString( 'skip' )
|
||||
|
||||
|
||||
def _ResetArchiveButton( self ):
|
||||
|
||||
self._archive_button.SetBitmapLabel( CC.GlobalBMPs.archive )
|
||||
self._archive_button.SetToolTipString( 'archive' )
|
||||
|
||||
|
||||
class FullscreenHoverFrameTopNavigableList( FullscreenHoverFrameTop ):
|
||||
|
||||
def _PopulateLeftButtons( self ):
|
||||
|
||||
self._first_button = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.first, HydrusGlobals.client_controller.pub, 'canvas_show_first', self._canvas_key )
|
||||
self._first_button.SetToolTipString( 'first' )
|
||||
|
||||
self._top_hbox.AddF( self._first_button, CC.FLAGS_VCENTER )
|
||||
|
||||
FullscreenHoverFrameTop._PopulateLeftButtons( self )
|
||||
|
||||
self._last_button = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.last, HydrusGlobals.client_controller.pub, 'canvas_show_last', self._canvas_key )
|
||||
self._last_button.SetToolTipString( 'last' )
|
||||
|
||||
self._top_hbox.AddF( self._last_button, CC.FLAGS_VCENTER )
|
||||
|
||||
|
||||
class FullscreenHoverFrameRatings( FullscreenHoverFrame ):
|
||||
|
||||
def __init__( self, parent, canvas_key ):
|
||||
|
|
|
@ -16,7 +16,6 @@ import wx
|
|||
class ListBox( wx.ScrolledWindow ):
|
||||
|
||||
TEXT_X_PADDING = 3
|
||||
delete_key_activates = False
|
||||
|
||||
def __init__( self, parent, min_height = 250 ):
|
||||
|
||||
|
@ -66,11 +65,18 @@ class ListBox( wx.ScrolledWindow ):
|
|||
|
||||
def _Activate( self ):
|
||||
|
||||
raise NotImplementedError()
|
||||
pass
|
||||
|
||||
|
||||
def _DeleteActivate( self ):
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def _AppendTerm( self, term ):
|
||||
|
||||
was_selected_before = term in self._selected_terms
|
||||
|
||||
if term in self._terms:
|
||||
|
||||
self._RemoveTerm( term )
|
||||
|
@ -81,6 +87,11 @@ class ListBox( wx.ScrolledWindow ):
|
|||
|
||||
self._terms_to_texts[ term ] = self._GetTextFromTerm( term )
|
||||
|
||||
if was_selected_before:
|
||||
|
||||
self._selected_terms.add( term )
|
||||
|
||||
|
||||
|
||||
def _Clear( self ):
|
||||
|
||||
|
@ -475,7 +486,11 @@ class ListBox( wx.ScrolledWindow ):
|
|||
|
||||
key_code = event.GetKeyCode()
|
||||
|
||||
if key_code in ( wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER ) or ( self.delete_key_activates and key_code in CC.DELETE_KEYS ):
|
||||
if key_code in CC.DELETE_KEYS:
|
||||
|
||||
self._DeleteActivate()
|
||||
|
||||
elif key_code in ( wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER ):
|
||||
|
||||
self._Activate()
|
||||
|
||||
|
@ -621,7 +636,11 @@ class ListBoxTags( ListBox ):
|
|||
|
||||
def _GetAllTagsForClipboard( self, with_counts = False ):
|
||||
|
||||
raise NotImplementedError()
|
||||
texts = list( self._terms_to_texts.values() )
|
||||
|
||||
texts.sort()
|
||||
|
||||
return texts
|
||||
|
||||
|
||||
def _GetNamespaceFromTerm( self, term ):
|
||||
|
@ -1088,7 +1107,6 @@ class ListBoxTagsPredicates( ListBoxTags ):
|
|||
|
||||
class ListBoxTagsActiveSearchPredicates( ListBoxTagsPredicates ):
|
||||
|
||||
delete_key_activates = True
|
||||
has_counts = False
|
||||
|
||||
def __init__( self, parent, page_key, initial_predicates = None ):
|
||||
|
@ -1124,6 +1142,11 @@ class ListBoxTagsActiveSearchPredicates( ListBoxTagsPredicates ):
|
|||
|
||||
|
||||
|
||||
def _DeleteActivate( self ):
|
||||
|
||||
self._Activate()
|
||||
|
||||
|
||||
def _EnterPredicates( self, predicates, permit_add = True, permit_remove = True ):
|
||||
|
||||
if len( predicates ) == 0:
|
||||
|
@ -1400,14 +1423,13 @@ class ListBoxTagsCensorship( ListBoxTags ):
|
|||
|
||||
class ListBoxTagsColourOptions( ListBoxTags ):
|
||||
|
||||
PROTECTED_TERMS = ( None, '' )
|
||||
can_spawn_new_windows = False
|
||||
|
||||
def __init__( self, parent, initial_namespace_colours ):
|
||||
|
||||
ListBoxTags.__init__( self, parent )
|
||||
|
||||
self._namespace_colours = dict( initial_namespace_colours )
|
||||
|
||||
for ( namespace, colour ) in initial_namespace_colours.items():
|
||||
|
||||
colour = tuple( colour ) # tuple to convert from list, for oooold users who have list colours
|
||||
|
@ -1415,12 +1437,21 @@ class ListBoxTagsColourOptions( ListBoxTags ):
|
|||
self._AppendTerm( ( namespace, colour ) )
|
||||
|
||||
|
||||
self._SortByText()
|
||||
|
||||
self._DataHasChanged()
|
||||
|
||||
|
||||
def _Activate( self ):
|
||||
|
||||
self._RemoveSelectedTerms()
|
||||
namespaces = [ namespace for ( namespace, colour ) in self._selected_terms ]
|
||||
|
||||
self._RemoveNamespaces( namespaces )
|
||||
|
||||
|
||||
def _DeleteActivate( self ):
|
||||
|
||||
self._Activate()
|
||||
|
||||
|
||||
def _GetTextFromTerm( self, term ):
|
||||
|
@ -1445,7 +1476,7 @@ class ListBoxTagsColourOptions( ListBoxTags ):
|
|||
|
||||
def _GetNamespaceColours( self ):
|
||||
|
||||
return self._namespace_colours
|
||||
return dict( self._terms )
|
||||
|
||||
|
||||
def _GetNamespaceFromTerm( self, term ):
|
||||
|
@ -1457,6 +1488,8 @@ class ListBoxTagsColourOptions( ListBoxTags ):
|
|||
|
||||
def _RemoveNamespaces( self, namespaces ):
|
||||
|
||||
namespaces = [ namespace for namespace in namespaces if namespace not in self.PROTECTED_TERMS ]
|
||||
|
||||
removees = [ ( existing_namespace, existing_colour ) for ( existing_namespace, existing_colour ) in self._terms if existing_namespace in namespaces ]
|
||||
|
||||
for removee in removees:
|
||||
|
@ -1483,14 +1516,14 @@ class ListBoxTagsColourOptions( ListBoxTags ):
|
|||
|
||||
self._AppendTerm( ( namespace, colour ) )
|
||||
|
||||
self._SortByText()
|
||||
|
||||
self._DataHasChanged()
|
||||
|
||||
|
||||
def GetNamespaceColours( self ):
|
||||
|
||||
namespace_colours = dict( self._terms )
|
||||
|
||||
return namespace_colours
|
||||
return self._GetNamespaceColours()
|
||||
|
||||
|
||||
def GetSelectedNamespaceColours( self ):
|
||||
|
@ -2073,11 +2106,6 @@ class ListBoxTagsSelectionHoverFrame( ListBoxTagsSelection ):
|
|||
|
||||
def _Activate( self ):
|
||||
|
||||
# if the hover window has focus when the manage tags spawns, then when it disappears, the main gui gets put as the next heir
|
||||
# so when manage tags closes, main gui pops to the front!
|
||||
|
||||
#self.GetParent().GiveParentFocus()
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'canvas_manage_tags', self._canvas_key )
|
||||
|
||||
|
||||
|
@ -2154,20 +2182,27 @@ class ListBoxTagsSelectionManagementPanel( ListBoxTagsSelection ):
|
|||
class ListBoxTagsSelectionTagsDialog( ListBoxTagsSelection ):
|
||||
|
||||
render_for_user = False
|
||||
delete_key_activates = True
|
||||
|
||||
def __init__( self, parent, callable ):
|
||||
def __init__( self, parent, add_func, delete_func ):
|
||||
|
||||
ListBoxTagsSelection.__init__( self, parent, include_counts = True, collapse_siblings = False )
|
||||
|
||||
self._callable = callable
|
||||
self._add_func = add_func
|
||||
self._delete_func = delete_func
|
||||
|
||||
|
||||
def _Activate( self ):
|
||||
|
||||
if len( self._selected_terms ) > 0:
|
||||
|
||||
self._callable( self._selected_terms )
|
||||
self._add_func( self._selected_terms )
|
||||
|
||||
|
||||
|
||||
def _DeleteActivate( self ):
|
||||
|
||||
if len( self._selected_terms ) > 0:
|
||||
|
||||
self._delete_func( self._selected_terms )
|
||||
|
||||
|
||||
|
|
|
@ -1189,8 +1189,7 @@ class ManagementPanelGalleryImport( ManagementPanel ):
|
|||
|
||||
self._waiting_politely_indicator = ClientGUICommon.GetWaitingPolitelyControl( self._import_queue_panel, self._page_key )
|
||||
|
||||
self._seed_cache_button = wx.BitmapButton( self._import_queue_panel, bitmap = CC.GlobalBMPs.seed_cache )
|
||||
self._seed_cache_button.Bind( wx.EVT_BUTTON, self.EventSeedCache )
|
||||
self._seed_cache_button = ClientGUICommon.BetterBitmapButton( self._import_queue_panel, CC.GlobalBMPs.seed_cache, self._SeedCache )
|
||||
self._seed_cache_button.SetToolTipString( 'open detailed file import status' )
|
||||
|
||||
self._files_pause_button = wx.BitmapButton( self._import_queue_panel, bitmap = CC.GlobalBMPs.pause )
|
||||
|
@ -1329,8 +1328,15 @@ class ManagementPanelGalleryImport( ManagementPanel ):
|
|||
|
||||
def file_download_hook( gauge_range, gauge_value ):
|
||||
|
||||
self._file_gauge.SetRange( gauge_range )
|
||||
self._file_gauge.SetValue( gauge_value )
|
||||
try:
|
||||
|
||||
self._file_gauge.SetRange( gauge_range )
|
||||
self._file_gauge.SetValue( gauge_value )
|
||||
|
||||
except wx.PyDeadObjectError:
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
||||
self._gallery_import.SetDownloadHook( file_download_hook )
|
||||
|
@ -1347,6 +1353,20 @@ class ManagementPanelGalleryImport( ManagementPanel ):
|
|||
self._gallery_import.Start( self._page_key )
|
||||
|
||||
|
||||
def _SeedCache( self ):
|
||||
|
||||
seed_cache = self._gallery_import.GetSeedCache()
|
||||
|
||||
title = 'file import status'
|
||||
frame_key = 'file_import_status'
|
||||
|
||||
frame = ClientGUITopLevelWindows.FrameThatTakesScrollablePanel( self, title, frame_key )
|
||||
|
||||
panel = ClientGUIScrolledPanelsEdit.EditSeedCachePanel( frame, self._controller, seed_cache )
|
||||
|
||||
frame.SetPanel( panel )
|
||||
|
||||
|
||||
def _Update( self ):
|
||||
|
||||
( pending_queries, gallery_status, ( overall_status, ( overall_value, overall_range ) ), files_paused, gallery_paused, cancellable ) = self._gallery_import.GetStatus()
|
||||
|
@ -1589,20 +1609,6 @@ class ManagementPanelGalleryImport( ManagementPanel ):
|
|||
|
||||
|
||||
|
||||
def EventSeedCache( self, event ):
|
||||
|
||||
seed_cache = self._gallery_import.GetSeedCache()
|
||||
|
||||
title = 'file import status'
|
||||
frame_key = 'file_import_status'
|
||||
|
||||
frame = ClientGUITopLevelWindows.FrameThatTakesScrollablePanel( self, title, frame_key )
|
||||
|
||||
panel = ClientGUIScrolledPanelsEdit.EditSeedCachePanel( frame, self._controller, seed_cache )
|
||||
|
||||
frame.SetPanel( panel )
|
||||
|
||||
|
||||
def SetSearchFocus( self, page_key ):
|
||||
|
||||
if page_key == self._page_key: self._query_input.SetFocus()
|
||||
|
@ -1630,8 +1636,7 @@ class ManagementPanelHDDImport( ManagementPanel ):
|
|||
self._current_action = wx.StaticText( self._import_queue_panel )
|
||||
self._overall_gauge = ClientGUICommon.Gauge( self._import_queue_panel )
|
||||
|
||||
self._seed_cache_button = wx.BitmapButton( self._import_queue_panel, bitmap = CC.GlobalBMPs.seed_cache )
|
||||
self._seed_cache_button.Bind( wx.EVT_BUTTON, self.EventSeedCache )
|
||||
self._seed_cache_button = ClientGUICommon.BetterBitmapButton( self._import_queue_panel, CC.GlobalBMPs.seed_cache, self._SeedCache )
|
||||
self._seed_cache_button.SetToolTipString( 'open detailed file import status' )
|
||||
|
||||
self._pause_button = wx.BitmapButton( self._import_queue_panel, bitmap = CC.GlobalBMPs.pause )
|
||||
|
@ -1670,6 +1675,20 @@ class ManagementPanelHDDImport( ManagementPanel ):
|
|||
self._hdd_import.Start( self._page_key )
|
||||
|
||||
|
||||
def _SeedCache( self ):
|
||||
|
||||
seed_cache = self._hdd_import.GetSeedCache()
|
||||
|
||||
title = 'file import status'
|
||||
frame_key = 'file_import_status'
|
||||
|
||||
frame = ClientGUITopLevelWindows.FrameThatTakesScrollablePanel( self, title, frame_key )
|
||||
|
||||
panel = ClientGUIScrolledPanelsEdit.EditSeedCachePanel( frame, self._controller, seed_cache )
|
||||
|
||||
frame.SetPanel( panel )
|
||||
|
||||
|
||||
def _Update( self ):
|
||||
|
||||
( ( overall_status, ( overall_value, overall_range ) ), paused ) = self._hdd_import.GetStatus()
|
||||
|
@ -1737,20 +1756,6 @@ class ManagementPanelHDDImport( ManagementPanel ):
|
|||
self._Update()
|
||||
|
||||
|
||||
def EventSeedCache( self, event ):
|
||||
|
||||
seed_cache = self._hdd_import.GetSeedCache()
|
||||
|
||||
title = 'file import status'
|
||||
frame_key = 'file_import_status'
|
||||
|
||||
frame = ClientGUITopLevelWindows.FrameThatTakesScrollablePanel( self, title, frame_key )
|
||||
|
||||
panel = ClientGUIScrolledPanelsEdit.EditSeedCachePanel( frame, self._controller, seed_cache )
|
||||
|
||||
frame.SetPanel( panel )
|
||||
|
||||
|
||||
def TestAbleToClose( self ):
|
||||
|
||||
( ( overall_status, ( overall_value, overall_range ) ), paused ) = self._hdd_import.GetStatus()
|
||||
|
@ -1798,8 +1803,7 @@ class ManagementPanelPageOfImagesImport( ManagementPanel ):
|
|||
|
||||
self._waiting_politely_indicator = ClientGUICommon.GetWaitingPolitelyControl( self._import_queue_panel, self._page_key )
|
||||
|
||||
self._seed_cache_button = wx.BitmapButton( self._import_queue_panel, bitmap = CC.GlobalBMPs.seed_cache )
|
||||
self._seed_cache_button.Bind( wx.EVT_BUTTON, self.EventSeedCache )
|
||||
self._seed_cache_button = ClientGUICommon.BetterBitmapButton( self._import_queue_panel, CC.GlobalBMPs.seed_cache, self._SeedCache )
|
||||
self._seed_cache_button.SetToolTipString( 'open detailed file import status' )
|
||||
|
||||
button_sizer = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
@ -1895,8 +1899,15 @@ class ManagementPanelPageOfImagesImport( ManagementPanel ):
|
|||
|
||||
def file_download_hook( gauge_range, gauge_value ):
|
||||
|
||||
self._file_gauge.SetRange( gauge_range )
|
||||
self._file_gauge.SetValue( gauge_value )
|
||||
try:
|
||||
|
||||
self._file_gauge.SetRange( gauge_range )
|
||||
self._file_gauge.SetValue( gauge_value )
|
||||
|
||||
except wx.PyDeadObjectError:
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
||||
self._page_of_images_import.SetDownloadHook( file_download_hook )
|
||||
|
@ -1913,6 +1924,20 @@ class ManagementPanelPageOfImagesImport( ManagementPanel ):
|
|||
self._page_of_images_import.Start( self._page_key )
|
||||
|
||||
|
||||
def _SeedCache( self ):
|
||||
|
||||
seed_cache = self._page_of_images_import.GetSeedCache()
|
||||
|
||||
title = 'file import status'
|
||||
frame_key = 'file_import_status'
|
||||
|
||||
frame = ClientGUITopLevelWindows.FrameThatTakesScrollablePanel( self, title, frame_key )
|
||||
|
||||
panel = ClientGUIScrolledPanelsEdit.EditSeedCachePanel( frame, self._controller, seed_cache )
|
||||
|
||||
frame.SetPanel( panel )
|
||||
|
||||
|
||||
def _Update( self ):
|
||||
|
||||
( pending_page_urls, parser_status, ( overall_status, ( overall_value, overall_range ) ), paused ) = self._page_of_images_import.GetStatus()
|
||||
|
@ -2114,20 +2139,6 @@ class ManagementPanelPageOfImagesImport( ManagementPanel ):
|
|||
self._Update()
|
||||
|
||||
|
||||
def EventSeedCache( self, event ):
|
||||
|
||||
seed_cache = self._page_of_images_import.GetSeedCache()
|
||||
|
||||
title = 'file import status'
|
||||
frame_key = 'file_import_status'
|
||||
|
||||
frame = ClientGUITopLevelWindows.FrameThatTakesScrollablePanel( self, title, frame_key )
|
||||
|
||||
panel = ClientGUIScrolledPanelsEdit.EditSeedCachePanel( frame, self._controller, seed_cache )
|
||||
|
||||
frame.SetPanel( panel )
|
||||
|
||||
|
||||
def SetSearchFocus( self, page_key ):
|
||||
|
||||
if page_key == self._page_key: self._page_url_input.SetFocus()
|
||||
|
@ -2828,8 +2839,7 @@ class ManagementPanelThreadWatcherImport( ManagementPanel ):
|
|||
|
||||
self._waiting_politely_indicator = ClientGUICommon.GetWaitingPolitelyControl( self._options_panel, self._page_key )
|
||||
|
||||
self._seed_cache_button = wx.BitmapButton( self._options_panel, bitmap = CC.GlobalBMPs.seed_cache )
|
||||
self._seed_cache_button.Bind( wx.EVT_BUTTON, self.EventSeedCache )
|
||||
self._seed_cache_button = ClientGUICommon.BetterBitmapButton( self._options_panel, CC.GlobalBMPs.seed_cache, self._SeedCache )
|
||||
self._seed_cache_button.SetToolTipString( 'open detailed file import status' )
|
||||
|
||||
self._pause_button = wx.BitmapButton( self._options_panel, bitmap = CC.GlobalBMPs.pause )
|
||||
|
@ -2899,8 +2909,15 @@ class ManagementPanelThreadWatcherImport( ManagementPanel ):
|
|||
|
||||
def file_download_hook( gauge_range, gauge_value ):
|
||||
|
||||
self._file_gauge.SetRange( gauge_range )
|
||||
self._file_gauge.SetValue( gauge_value )
|
||||
try:
|
||||
|
||||
self._file_gauge.SetRange( gauge_range )
|
||||
self._file_gauge.SetValue( gauge_value )
|
||||
|
||||
except wx.PyDeadObjectError:
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
||||
self._thread_watcher_import.SetDownloadHook( file_download_hook )
|
||||
|
@ -2924,6 +2941,20 @@ class ManagementPanelThreadWatcherImport( ManagementPanel ):
|
|||
self._Update()
|
||||
|
||||
|
||||
def _SeedCache( self ):
|
||||
|
||||
seed_cache = self._thread_watcher_import.GetSeedCache()
|
||||
|
||||
title = 'file import status'
|
||||
frame_key = 'file_import_status'
|
||||
|
||||
frame = ClientGUITopLevelWindows.FrameThatTakesScrollablePanel( self, title, frame_key )
|
||||
|
||||
panel = ClientGUIScrolledPanelsEdit.EditSeedCachePanel( frame, self._controller, seed_cache )
|
||||
|
||||
frame.SetPanel( panel )
|
||||
|
||||
|
||||
def _Update( self ):
|
||||
|
||||
if self._thread_watcher_import.HasThread():
|
||||
|
@ -3062,7 +3093,10 @@ class ManagementPanelThreadWatcherImport( ManagementPanel ):
|
|||
|
||||
self._thread_watcher_import.Start( self._page_key )
|
||||
|
||||
else: event.Skip()
|
||||
else:
|
||||
|
||||
event.Skip()
|
||||
|
||||
|
||||
|
||||
def EventMenu( self, event ):
|
||||
|
@ -3096,20 +3130,6 @@ class ManagementPanelThreadWatcherImport( ManagementPanel ):
|
|||
self._Update()
|
||||
|
||||
|
||||
def EventSeedCache( self, event ):
|
||||
|
||||
seed_cache = self._thread_watcher_import.GetSeedCache()
|
||||
|
||||
title = 'file import status'
|
||||
frame_key = 'file_import_status'
|
||||
|
||||
frame = ClientGUITopLevelWindows.FrameThatTakesScrollablePanel( self, title, frame_key )
|
||||
|
||||
panel = ClientGUIScrolledPanelsEdit.EditSeedCachePanel( frame, self._controller, seed_cache )
|
||||
|
||||
frame.SetPanel( panel )
|
||||
|
||||
|
||||
def EventTimesToCheck( self, event ):
|
||||
|
||||
times_to_check = self._thread_times_to_check.GetValue()
|
||||
|
@ -3172,8 +3192,7 @@ class ManagementPanelURLsImport( ManagementPanel ):
|
|||
|
||||
self._waiting_politely_indicator = ClientGUICommon.GetWaitingPolitelyControl( self._url_panel, self._page_key )
|
||||
|
||||
self._seed_cache_button = wx.BitmapButton( self._url_panel, bitmap = CC.GlobalBMPs.seed_cache )
|
||||
self._seed_cache_button.Bind( wx.EVT_BUTTON, self.EventSeedCache )
|
||||
self._seed_cache_button = ClientGUICommon.BetterBitmapButton( self._url_panel, CC.GlobalBMPs.seed_cache, self._SeedCache )
|
||||
self._seed_cache_button.SetToolTipString( 'open detailed file import status' )
|
||||
|
||||
self._url_input = wx.TextCtrl( self._url_panel, style = wx.TE_PROCESS_ENTER )
|
||||
|
@ -3227,8 +3246,15 @@ class ManagementPanelURLsImport( ManagementPanel ):
|
|||
|
||||
def file_download_hook( gauge_range, gauge_value ):
|
||||
|
||||
self._file_gauge.SetRange( gauge_range )
|
||||
self._file_gauge.SetValue( gauge_value )
|
||||
try:
|
||||
|
||||
self._file_gauge.SetRange( gauge_range )
|
||||
self._file_gauge.SetValue( gauge_value )
|
||||
|
||||
except wx.PyDeadObjectError:
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
||||
self._urls_import.SetDownloadHook( file_download_hook )
|
||||
|
@ -3242,6 +3268,20 @@ class ManagementPanelURLsImport( ManagementPanel ):
|
|||
self._urls_import.Start( self._page_key )
|
||||
|
||||
|
||||
def _SeedCache( self ):
|
||||
|
||||
seed_cache = self._urls_import.GetSeedCache()
|
||||
|
||||
title = 'file import status'
|
||||
frame_key = 'file_import_status'
|
||||
|
||||
frame = ClientGUITopLevelWindows.FrameThatTakesScrollablePanel( self, title, frame_key )
|
||||
|
||||
panel = ClientGUIScrolledPanelsEdit.EditSeedCachePanel( frame, self._controller, seed_cache )
|
||||
|
||||
frame.SetPanel( panel )
|
||||
|
||||
|
||||
def _Update( self ):
|
||||
|
||||
( ( overall_status, ( overall_value, overall_range ) ), paused ) = self._urls_import.GetStatus()
|
||||
|
@ -3374,20 +3414,6 @@ class ManagementPanelURLsImport( ManagementPanel ):
|
|||
self._Update()
|
||||
|
||||
|
||||
def EventSeedCache( self, event ):
|
||||
|
||||
seed_cache = self._urls_import.GetSeedCache()
|
||||
|
||||
title = 'file import status'
|
||||
frame_key = 'file_import_status'
|
||||
|
||||
frame = ClientGUITopLevelWindows.FrameThatTakesScrollablePanel( self, title, frame_key )
|
||||
|
||||
panel = ClientGUIScrolledPanelsEdit.EditSeedCachePanel( frame, self._controller, seed_cache )
|
||||
|
||||
frame.SetPanel( panel )
|
||||
|
||||
|
||||
def SetSearchFocus( self, page_key ):
|
||||
|
||||
if page_key == self._page_key: self._url_input.SetFocus()
|
||||
|
|
|
@ -893,9 +893,9 @@ class MediaPanel( ClientMedia.ListeningMediaList, wx.ScrolledWindow ):
|
|||
|
||||
contents = [ HydrusNetwork.Content( HC.CONTENT_TYPE_FILES, [ hash ] ) for hash in hashes ]
|
||||
|
||||
subject_identifiers = [ HydrusData.AccountIdentifier( content = content ) for content in contents ]
|
||||
subject_accounts = 'blah' # fetch subjects from server with the contents
|
||||
|
||||
with ClientGUIDialogs.DialogModifyAccounts( self, file_service_key, subject_identifiers ) as dlg: dlg.ShowModal()
|
||||
with ClientGUIDialogs.DialogModifyAccounts( self, file_service_key, subject_accounts ) as dlg: dlg.ShowModal()
|
||||
|
||||
self.SetFocus()
|
||||
|
||||
|
|
|
@ -257,7 +257,7 @@ class ReviewServicePanel( wx.Panel ):
|
|||
|
||||
if external_port is None: external_port = info[ 'port' ]
|
||||
|
||||
url = 'http://' + external_ip + ':' + str( external_port ) + '/gallery?share_key=' + share_key.encode( 'hex' )
|
||||
url = 'http://' + external_ip + ':' + HydrusData.ToUnicode( external_port ) + '/gallery?share_key=' + share_key.encode( 'hex' )
|
||||
|
||||
self._controller.pub( 'clipboard', 'text', url )
|
||||
|
||||
|
@ -789,7 +789,7 @@ class ReviewServicePanel( wx.Panel ):
|
|||
|
||||
HydrusData.ShowException( e )
|
||||
|
||||
wx.CallAfter( wx.MessageBox, str( e ) )
|
||||
wx.CallAfter( wx.MessageBox, HydrusData.ToUnicode( e ) )
|
||||
|
||||
|
||||
wx.CallAfter( self._Refresh )
|
||||
|
|
|
@ -1869,7 +1869,7 @@ class ManageParsingScriptsPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
except Exception as e:
|
||||
|
||||
wx.MessageBox( str( e ) )
|
||||
wx.MessageBox( HydrusData.ToUnicode( e ) )
|
||||
|
||||
return
|
||||
|
||||
|
|
|
@ -766,8 +766,7 @@ class EditSubscriptionPanel( ClientGUIScrolledPanels.EditPanel ):
|
|||
|
||||
self._paused = wx.CheckBox( self._control_panel )
|
||||
|
||||
self._seed_cache_button = wx.BitmapButton( self._control_panel, bitmap = CC.GlobalBMPs.seed_cache )
|
||||
self._seed_cache_button.Bind( wx.EVT_BUTTON, self.EventSeedCache )
|
||||
self._seed_cache_button = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.seed_cache, self._SeedCache )
|
||||
self._seed_cache_button.SetToolTipString( 'open detailed url cache status' )
|
||||
|
||||
self._retry_failed = ClientGUICommon.BetterButton( self._control_panel, 'retry failed', self.RetryFailed )
|
||||
|
@ -1055,25 +1054,7 @@ class EditSubscriptionPanel( ClientGUIScrolledPanels.EditPanel ):
|
|||
wx.CallAfter( self.ProcessEvent, event )
|
||||
|
||||
|
||||
def CheckNow( self ):
|
||||
|
||||
self._check_now = True
|
||||
|
||||
self._UpdateCommandButtons()
|
||||
self._UpdateLastNextCheck()
|
||||
|
||||
|
||||
def EventBooruSelected( self, event ):
|
||||
|
||||
self._ConfigureImportTagOptions()
|
||||
|
||||
|
||||
def EventPeriodChanged( self, event ):
|
||||
|
||||
self._UpdateLastNextCheck()
|
||||
|
||||
|
||||
def EventSeedCache( self, event ):
|
||||
def _SeedCache( self ):
|
||||
|
||||
dupe_seed_cache = self._seed_cache.Duplicate()
|
||||
|
||||
|
@ -1092,6 +1073,23 @@ class EditSubscriptionPanel( ClientGUIScrolledPanels.EditPanel ):
|
|||
|
||||
|
||||
|
||||
|
||||
def CheckNow( self ):
|
||||
|
||||
self._check_now = True
|
||||
|
||||
self._UpdateCommandButtons()
|
||||
self._UpdateLastNextCheck()
|
||||
|
||||
|
||||
def EventBooruSelected( self, event ):
|
||||
|
||||
self._ConfigureImportTagOptions()
|
||||
|
||||
|
||||
def EventPeriodChanged( self, event ):
|
||||
|
||||
self._UpdateLastNextCheck()
|
||||
|
||||
|
||||
def EventSiteChanged( self, event ):
|
||||
|
|
|
@ -15,6 +15,7 @@ import ClientGUITagSuggestions
|
|||
import ClientGUITopLevelWindows
|
||||
import ClientImporting
|
||||
import ClientMedia
|
||||
import ClientRatings
|
||||
import ClientSerialisable
|
||||
import ClientServices
|
||||
import collections
|
||||
|
@ -678,7 +679,7 @@ class ManageClientServicesPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
except HydrusExceptions.NetworkException as e:
|
||||
|
||||
wx.MessageBox( 'Problem with that address: ' + str( e ) )
|
||||
wx.MessageBox( 'Problem with that address: ' + HydrusData.ToUnicode( e ) )
|
||||
|
||||
|
||||
|
||||
|
@ -867,7 +868,7 @@ class ManageClientServicesPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
except HydrusExceptions.NetworkException as e:
|
||||
|
||||
wx.MessageBox( 'Network problem: ' + str( e ) )
|
||||
wx.MessageBox( 'Network problem: ' + HydrusData.ToUnicode( e ) )
|
||||
|
||||
return
|
||||
|
||||
|
@ -1034,29 +1035,7 @@ class ManageClientServicesPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
ClientGUICommon.StaticBox.__init__( self, parent, 'ratings' )
|
||||
|
||||
# shape
|
||||
# colours
|
||||
|
||||
self._st = wx.StaticText( self )
|
||||
'''
|
||||
if service_type in HC.RATINGS_SERVICES:
|
||||
|
||||
self._local_rating_panel = ClientGUICommon.StaticBox( self, 'local rating configuration' )
|
||||
|
||||
if service_type == HC.LOCAL_RATING_NUMERICAL:
|
||||
|
||||
num_stars = info[ 'num_stars' ]
|
||||
|
||||
self._num_stars = wx.SpinCtrl( self._local_rating_panel, min = 1, max = 20 )
|
||||
self._num_stars.SetValue( num_stars )
|
||||
|
||||
allow_zero = info[ 'allow_zero' ]
|
||||
|
||||
self._allow_zero = wx.CheckBox( self._local_rating_panel )
|
||||
self._allow_zero.SetValue( allow_zero )
|
||||
|
||||
|
||||
self._shape = ClientGUICommon.BetterChoice( self._local_rating_panel )
|
||||
self._shape = ClientGUICommon.BetterChoice( self )
|
||||
|
||||
self._shape.Append( 'circle', ClientRatings.CIRCLE )
|
||||
self._shape.Append( 'square', ClientRatings.SQUARE )
|
||||
|
@ -1066,8 +1045,8 @@ class ManageClientServicesPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
for colour_type in [ ClientRatings.LIKE, ClientRatings.DISLIKE, ClientRatings.NULL, ClientRatings.MIXED ]:
|
||||
|
||||
border_ctrl = wx.ColourPickerCtrl( self._local_rating_panel )
|
||||
fill_ctrl = wx.ColourPickerCtrl( self._local_rating_panel )
|
||||
border_ctrl = wx.ColourPickerCtrl( self )
|
||||
fill_ctrl = wx.ColourPickerCtrl( self )
|
||||
|
||||
border_ctrl.SetMaxSize( ( 20, -1 ) )
|
||||
fill_ctrl.SetMaxSize( ( 20, -1 ) )
|
||||
|
@ -1075,17 +1054,11 @@ class ManageClientServicesPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
self._colour_ctrls[ colour_type ] = ( border_ctrl, fill_ctrl )
|
||||
|
||||
|
||||
#
|
||||
|
||||
self._shape.SelectClientData( dictionary[ 'shape' ] )
|
||||
|
||||
if service_type in HC.RATINGS_SERVICES:
|
||||
|
||||
self._shape.SelectClientData( info[ 'shape' ] )
|
||||
|
||||
colours = info[ 'colours' ]
|
||||
|
||||
for colour_type in colours:
|
||||
|
||||
( border_rgb, fill_rgb ) = colours[ colour_type ]
|
||||
for ( colour_type, ( border_rgb, fill_rgb ) ) in dictionary[ 'colours' ]:
|
||||
|
||||
( border_ctrl, fill_ctrl ) = self._colour_ctrls[ colour_type ]
|
||||
|
||||
|
@ -1093,19 +1066,10 @@ class ManageClientServicesPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
fill_ctrl.SetColour( wx.Colour( *fill_rgb ) )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ):
|
||||
#
|
||||
|
||||
rows = []
|
||||
|
||||
if service_type == HC.LOCAL_RATING_NUMERICAL:
|
||||
|
||||
rows.append( ( 'number of \'stars\': ', self._num_stars ) )
|
||||
rows.append( ( 'allow a zero rating: ', self._allow_zero ) )
|
||||
|
||||
|
||||
rows.append( ( 'shape: ', self._shape ) )
|
||||
|
||||
for colour_type in [ ClientRatings.LIKE, ClientRatings.DISLIKE, ClientRatings.NULL, ClientRatings.MIXED ]:
|
||||
|
@ -1125,38 +1089,20 @@ class ManageClientServicesPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
rows.append( ( 'border/fill for ' + colour_text + ': ', hbox ) )
|
||||
|
||||
|
||||
gridbox = ClientGUICommon.WrapInGrid( self._local_rating_panel, rows )
|
||||
gridbox = ClientGUICommon.WrapInGrid( self, rows )
|
||||
|
||||
self._local_rating_panel.AddF( gridbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
|
||||
|
||||
vbox.AddF( self._local_rating_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self.AddF( gridbox, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
|
||||
|
||||
if service_type in HC.RATINGS_SERVICES:
|
||||
def GetValue( self ):
|
||||
|
||||
if service_type == HC.LOCAL_RATING_NUMERICAL:
|
||||
|
||||
num_stars = self._num_stars.GetValue()
|
||||
allow_zero = self._allow_zero.GetValue()
|
||||
|
||||
if num_stars == 1 and not allow_zero:
|
||||
|
||||
allow_zero = True
|
||||
|
||||
|
||||
info[ 'num_stars' ] = num_stars
|
||||
info[ 'allow_zero' ] = allow_zero
|
||||
|
||||
dictionary_part = {}
|
||||
|
||||
info[ 'shape' ] = self._shape.GetChoice()
|
||||
dictionary_part[ 'shape' ] = self._shape.GetChoice()
|
||||
|
||||
colours = {}
|
||||
dictionary_part[ 'colours' ] = {}
|
||||
|
||||
for colour_type in self._colour_ctrls:
|
||||
|
||||
( border_ctrl, fill_ctrl ) = self._colour_ctrls[ colour_type ]
|
||||
for ( colour_type, ( border_ctrl, fill_ctrl ) ) in self._colour_ctrls.items():
|
||||
|
||||
border_colour = border_ctrl.GetColour()
|
||||
|
||||
|
@ -1166,26 +1112,9 @@ class ManageClientServicesPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
fill_rgb = ( fill_colour.Red(), fill_colour.Green(), fill_colour.Blue() )
|
||||
|
||||
colours[ colour_type ] = ( border_rgb, fill_rgb )
|
||||
dictionary_part[ 'colours' ][ colour_type ] = ( border_rgb, fill_rgb )
|
||||
|
||||
|
||||
info[ 'colours' ] = colours
|
||||
|
||||
|
||||
'''
|
||||
#
|
||||
|
||||
self._st.SetLabelText( 'This is a ratings service. This box will get regain colour and star options in a future update.' )
|
||||
|
||||
#
|
||||
|
||||
self.AddF( self._st, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
def GetValue( self ):
|
||||
|
||||
dictionary_part = {}
|
||||
|
||||
return dictionary_part
|
||||
|
||||
|
||||
|
@ -1196,24 +1125,41 @@ class ManageClientServicesPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
ClientGUICommon.StaticBox.__init__( self, parent, 'numerical ratings' )
|
||||
|
||||
# num_stars
|
||||
# allow_zero
|
||||
|
||||
self._st = wx.StaticText( self )
|
||||
self._num_stars = wx.SpinCtrl( self, min = 1, max = 20 )
|
||||
self._allow_zero = wx.CheckBox( self )
|
||||
|
||||
#
|
||||
|
||||
self._st.SetLabelText( 'This is an numerical ratings service. This box will get regain its options in a future update.' )
|
||||
self._num_stars.SetValue( dictionary[ 'num_stars' ] )
|
||||
self._allow_zero.SetValue( dictionary[ 'allow_zero' ] )
|
||||
|
||||
#
|
||||
|
||||
self.AddF( self._st, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
rows = []
|
||||
|
||||
rows.append( ( 'number of \'stars\': ', self._num_stars ) )
|
||||
rows.append( ( 'allow a zero rating: ', self._allow_zero ) )
|
||||
|
||||
gridbox = ClientGUICommon.WrapInGrid( self, rows )
|
||||
|
||||
self.AddF( gridbox, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
def GetValue( self ):
|
||||
|
||||
dictionary_part = {}
|
||||
|
||||
num_stars = self._num_stars.GetValue()
|
||||
allow_zero = self._allow_zero.GetValue()
|
||||
|
||||
if num_stars == 1 and not allow_zero:
|
||||
|
||||
allow_zero = True
|
||||
|
||||
|
||||
dictionary_part[ 'num_stars' ] = num_stars
|
||||
dictionary_part[ 'allow_zero' ] = allow_zero
|
||||
|
||||
return dictionary_part
|
||||
|
||||
|
||||
|
@ -1224,7 +1170,7 @@ class ManageClientServicesPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
ClientGUICommon.StaticBox.__init__( self, parent, 'ipfs' )
|
||||
|
||||
# test creds
|
||||
# test creds and fetch version
|
||||
# multihash_prefix
|
||||
'''
|
||||
if service_type == HC.IPFS:
|
||||
|
@ -1235,7 +1181,7 @@ class ManageClientServicesPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
tts = 'When you tell the client to copy the ipfs multihash to your clipboard, it will prefix it with this.'
|
||||
tts += os.linesep * 2
|
||||
tts += 'Use this if you would really like to copy a full gateway url with that action. For instance, you could put here:'
|
||||
tts += 'Use this if you would rather copy a full gateway url with that action. For instance, you could put here:'
|
||||
tts += os.linesep * 2
|
||||
tts += 'http://127.0.0.1:8080/ipfs/'
|
||||
tts += os.linesep
|
||||
|
@ -1760,6 +1706,8 @@ class ManageOptionsPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
self._waiting_politely_text = wx.CheckBox( general )
|
||||
|
||||
self._verify_regular_https = wx.CheckBox( general )
|
||||
|
||||
#
|
||||
|
||||
gallery_downloader = ClientGUICommon.StaticBox( self, 'gallery downloader' )
|
||||
|
@ -1781,6 +1729,8 @@ class ManageOptionsPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
self._website_download_polite_wait.SetValue( HC.options[ 'website_download_polite_wait' ] )
|
||||
self._waiting_politely_text.SetValue( self._new_options.GetBoolean( 'waiting_politely_text' ) )
|
||||
|
||||
self._verify_regular_https.SetValue( self._new_options.GetBoolean( 'verify_regular_https' ) )
|
||||
|
||||
self._gallery_file_limit.SetValue( HC.options[ 'gallery_file_limit' ] )
|
||||
|
||||
( times_to_check, check_period ) = HC.options[ 'thread_checker_timings' ]
|
||||
|
@ -1795,6 +1745,7 @@ class ManageOptionsPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
rows.append( ( 'seconds to politely wait between gallery/thread url requests: ', self._website_download_polite_wait ) )
|
||||
rows.append( ( 'instead of the traffic light waiting politely indicator, use text: ', self._waiting_politely_text ) )
|
||||
rows.append( ( 'BUGFIX: verify regular https traffic:', self._verify_regular_https ) )
|
||||
|
||||
gridbox = ClientGUICommon.WrapInGrid( general, rows )
|
||||
|
||||
|
@ -1830,6 +1781,7 @@ class ManageOptionsPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
HC.options[ 'website_download_polite_wait' ] = self._website_download_polite_wait.GetValue()
|
||||
self._new_options.SetBoolean( 'waiting_politely_text', self._waiting_politely_text.GetValue() )
|
||||
self._new_options.SetBoolean( 'verify_regular_https', self._verify_regular_https.GetValue() )
|
||||
HC.options[ 'gallery_file_limit' ] = self._gallery_file_limit.GetValue()
|
||||
HC.options[ 'thread_checker_timings' ] = ( self._thread_times_to_check.GetValue(), self._thread_check_period.GetValue() )
|
||||
|
||||
|
@ -4187,7 +4139,7 @@ class ManageSubscriptionsPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
except Exception as e:
|
||||
|
||||
wx.MessageBox( str( e ) )
|
||||
wx.MessageBox( HydrusData.ToUnicode( e ) )
|
||||
|
||||
return
|
||||
|
||||
|
@ -4483,7 +4435,7 @@ class ManageTagsPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
self._tags_box_sorter = ClientGUICommon.StaticBoxSorterForListBoxTags( self, 'tags' )
|
||||
|
||||
self._tags_box = ClientGUIListBoxes.ListBoxTagsSelectionTagsDialog( self._tags_box_sorter, self.AddTags )
|
||||
self._tags_box = ClientGUIListBoxes.ListBoxTagsSelectionTagsDialog( self._tags_box_sorter, self.AddTags, self.RemoveTags )
|
||||
|
||||
self._tags_box_sorter.SetTagsBox( self._tags_box )
|
||||
|
||||
|
@ -4938,9 +4890,9 @@ class ManageTagsPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
if len( contents ) > 0:
|
||||
|
||||
subject_identifiers = [ HydrusData.AccountIdentifier( content = content ) for content in contents ]
|
||||
subject_accounts = 'blah' # fetch subjects from the server using the contents
|
||||
|
||||
with ClientGUIDialogs.DialogModifyAccounts( self, self._tag_service_key, subject_identifiers ) as dlg: dlg.ShowModal()
|
||||
with ClientGUIDialogs.DialogModifyAccounts( self, self._tag_service_key, subject_accounts ) as dlg: dlg.ShowModal()
|
||||
|
||||
|
||||
|
||||
|
@ -5001,6 +4953,14 @@ class ManageTagsPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
wx.PostEvent( self, wx.CommandEvent( commandType = wx.wxEVT_COMMAND_MENU_SELECTED, winid = ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'ok' ) ) )
|
||||
|
||||
|
||||
def RemoveTags( self, tags ):
|
||||
|
||||
if len( tags ) > 0:
|
||||
|
||||
self._AddTags( tags, only_remove = True )
|
||||
|
||||
|
||||
|
||||
def SetMedia( self, media ):
|
||||
|
||||
if media is None:
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
import wx
|
||||
|
||||
class ShortcutsHandler( object ):
|
||||
|
||||
def __init__( self, parent, initial_shortcuts = None ):
|
||||
|
||||
if initial_shortcuts is None:
|
||||
|
||||
initial_shortcuts = []
|
||||
|
||||
|
||||
self._parent = parent
|
||||
self._all_shortcuts = {}
|
||||
|
||||
for shortcuts in initial_shortcuts:
|
||||
|
||||
self._all_shortcuts[ shortcuts.GetName() ] = shortcuts
|
||||
|
||||
|
||||
self._parent.Bind( wx.EVT_CHAR_HOOK, self.EventCharHook )
|
||||
self._parent.Bind( wx.EVT_MOUSE_EVENTS, self.EventMouse )
|
||||
|
||||
|
||||
def EventCharHook( self, event ):
|
||||
|
||||
# determine if the event came from a textctrl or a different tlp than my parent, in which case we want to skip it
|
||||
|
||||
# fetch the event details, convert to modifier and key
|
||||
# check with all my shortcuts for an action
|
||||
|
||||
# if action exists, post it to parent
|
||||
# else:
|
||||
|
||||
event.Skip()
|
||||
|
||||
|
||||
def EventMouse( self, event ):
|
||||
|
||||
# fetch the event details, convert to modifier and key
|
||||
# check with all my shortcuts for an action
|
||||
|
||||
# if action exists, post it to parent
|
||||
# else:
|
||||
|
||||
event.Skip()
|
||||
|
||||
|
||||
def AddShortcuts( self, shortcuts ):
|
||||
|
||||
self._all_shortcuts[ shortcuts.GetName() ] = shortcuts
|
||||
|
||||
|
||||
def RemoveShortcuts( self, shortcuts_name ):
|
||||
|
||||
if shortcuts_name in self._all_shortcuts:
|
||||
|
||||
del self._all_shortcuts[ shortcuts_name ]
|
||||
|
||||
|
|
@ -96,6 +96,13 @@ class ListBoxTagsSuggestionsRelated( ClientGUIListBoxes.ListBoxTagsPredicates ):
|
|||
|
||||
|
||||
|
||||
def _GetTextFromTerm( self, term ):
|
||||
|
||||
predicate = term
|
||||
|
||||
return predicate.GetUnicode( with_count = False )
|
||||
|
||||
|
||||
def SetPredicates( self, predicates ):
|
||||
|
||||
self._Clear()
|
||||
|
|
|
@ -693,11 +693,21 @@ class HDDImport( HydrusSerialisable.SerialisableBase ):
|
|||
|
||||
try:
|
||||
|
||||
if not os.path.exists( path ):
|
||||
|
||||
raise Exception( 'Source file does not exist!' )
|
||||
|
||||
|
||||
( os_file_handle, temp_path ) = HydrusPaths.GetTempPath()
|
||||
|
||||
try:
|
||||
|
||||
HydrusPaths.MirrorFile( path, temp_path )
|
||||
copied = HydrusPaths.MirrorFile( path, temp_path )
|
||||
|
||||
if not copied:
|
||||
|
||||
raise Exception( 'File failed to copy--see log for error.' )
|
||||
|
||||
|
||||
client_files_manager = HydrusGlobals.client_controller.GetClientFilesManager()
|
||||
|
||||
|
@ -1120,7 +1130,12 @@ class ImportFolder( HydrusSerialisable.SerialisableBaseNamed ):
|
|||
|
||||
try:
|
||||
|
||||
HydrusPaths.MirrorFile( path, temp_path )
|
||||
copied = HydrusPaths.MirrorFile( path, temp_path )
|
||||
|
||||
if not copied:
|
||||
|
||||
raise Exception( 'File failed to copy--see log for error.' )
|
||||
|
||||
|
||||
client_files_manager = HydrusGlobals.client_controller.GetClientFilesManager()
|
||||
|
||||
|
|
|
@ -840,7 +840,9 @@ class HTTPConnection( object ):
|
|||
if self._scheme == 'http': self._connection = httplib.HTTPConnection( self._host, self._port, timeout = self._timeout )
|
||||
elif self._scheme == 'https':
|
||||
|
||||
if self._hydrus_network:
|
||||
new_options = HydrusGlobals.client_controller.GetNewOptions()
|
||||
|
||||
if self._hydrus_network or not new_options.GetBoolean( 'verify_regular_https' ):
|
||||
|
||||
# this negotiates decent encryption but won't check hostname or the certificate
|
||||
|
||||
|
|
|
@ -786,7 +786,7 @@ class ServiceRestricted( ServiceRemote ):
|
|||
|
||||
else:
|
||||
|
||||
self._DelayFutureRequests( str( e ) )
|
||||
self._DelayFutureRequests( HydrusData.ToUnicode( e ) )
|
||||
|
||||
|
||||
|
||||
|
@ -1747,7 +1747,7 @@ class ServiceIPFS( ServiceRemote ):
|
|||
|
||||
except HydrusExceptions.NetworkException as e:
|
||||
|
||||
if 'not pinned' not in str( e ):
|
||||
if 'not pinned' not in HydrusData.ToUnicode( e ):
|
||||
|
||||
raise
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ options = {}
|
|||
# Misc
|
||||
|
||||
NETWORK_VERSION = 18
|
||||
SOFTWARE_VERSION = 248
|
||||
SOFTWARE_VERSION = 249
|
||||
|
||||
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )
|
||||
|
||||
|
@ -70,6 +70,11 @@ bandwidth_type_string_lookup = {}
|
|||
bandwidth_type_string_lookup[ BANDWIDTH_TYPE_DATA ] = 'data'
|
||||
bandwidth_type_string_lookup[ BANDWIDTH_TYPE_REQUESTS ] = 'requests'
|
||||
|
||||
CONTENT_MERGE_ACTION_DO_NOTHING = 0
|
||||
CONTENT_MERGE_ACTION_COPY = 1
|
||||
CONTENT_MERGE_ACTION_MOVE = 2
|
||||
CONTENT_MERGE_ACTION_UNION = 3
|
||||
|
||||
CONTENT_STATUS_CURRENT = 0
|
||||
CONTENT_STATUS_PENDING = 1
|
||||
CONTENT_STATUS_DELETED = 2
|
||||
|
|
|
@ -129,6 +129,8 @@ class HydrusDB( object ):
|
|||
self._db_name = db_name
|
||||
self._no_wal = no_wal
|
||||
|
||||
self._in_transaction = False
|
||||
|
||||
self._connection_timestamp = 0
|
||||
|
||||
main_db_filename = db_name
|
||||
|
@ -194,7 +196,10 @@ class HydrusDB( object ):
|
|||
|
||||
time.sleep( self.UPDATE_WAIT )
|
||||
|
||||
try: self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
try:
|
||||
|
||||
self._BeginImmediate()
|
||||
|
||||
except Exception as e:
|
||||
|
||||
raise HydrusExceptions.DBAccessException( HydrusData.ToUnicode( e ) )
|
||||
|
@ -204,7 +209,7 @@ class HydrusDB( object ):
|
|||
|
||||
self._UpdateDB( version )
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._is_db_updated = True
|
||||
|
||||
|
@ -214,7 +219,7 @@ class HydrusDB( object ):
|
|||
|
||||
try:
|
||||
|
||||
self._c.execute( 'ROLLBACK;' )
|
||||
self._Rollback()
|
||||
|
||||
except Exception as rollback_e:
|
||||
|
||||
|
@ -271,6 +276,20 @@ class HydrusDB( object ):
|
|||
|
||||
|
||||
|
||||
def _BeginImmediate( self ):
|
||||
|
||||
if self._in_transaction:
|
||||
|
||||
HydrusData.Print( 'Received a call to begin, but was already in a transaction!' )
|
||||
|
||||
else:
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
|
||||
self._in_transaction = True
|
||||
|
||||
|
||||
|
||||
def _CleanUpCaches( self ):
|
||||
|
||||
pass
|
||||
|
@ -280,6 +299,11 @@ class HydrusDB( object ):
|
|||
|
||||
if self._db is not None:
|
||||
|
||||
if self._in_transaction:
|
||||
|
||||
self._Commit()
|
||||
|
||||
|
||||
self._c.close()
|
||||
self._db.close()
|
||||
|
||||
|
@ -291,6 +315,20 @@ class HydrusDB( object ):
|
|||
|
||||
|
||||
|
||||
def _Commit( self ):
|
||||
|
||||
if self._in_transaction:
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
|
||||
self._in_transaction = False
|
||||
|
||||
else:
|
||||
|
||||
HydrusData.Print( 'Received a call to commit, but was not in a transaction!' )
|
||||
|
||||
|
||||
|
||||
def _CreateDB( self ):
|
||||
|
||||
raise NotImplementedError()
|
||||
|
@ -447,6 +485,11 @@ class HydrusDB( object ):
|
|||
|
||||
|
||||
|
||||
def _InitDiskCache( self ):
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def _InitExternalDatabases( self ):
|
||||
|
||||
pass
|
||||
|
@ -463,25 +506,19 @@ class HydrusDB( object ):
|
|||
|
||||
( action, args, kwargs ) = job.GetCallableTuple()
|
||||
|
||||
in_transaction = False
|
||||
|
||||
try:
|
||||
|
||||
if job_type in ( 'read_write', 'write' ):
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
|
||||
in_transaction = True
|
||||
self._BeginImmediate()
|
||||
|
||||
|
||||
if job_type in ( 'read', 'read_write' ): result = self._Read( action, *args, **kwargs )
|
||||
elif job_type in ( 'write' ): result = self._Write( action, *args, **kwargs )
|
||||
|
||||
if in_transaction:
|
||||
if self._in_transaction:
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
|
||||
in_transaction = False
|
||||
self._Commit()
|
||||
|
||||
|
||||
for ( topic, args, kwargs ) in self._pubsubs:
|
||||
|
@ -496,11 +533,11 @@ class HydrusDB( object ):
|
|||
|
||||
except Exception as e:
|
||||
|
||||
if in_transaction:
|
||||
if self._in_transaction:
|
||||
|
||||
try:
|
||||
|
||||
self._c.execute( 'ROLLBACK;' )
|
||||
self._Rollback()
|
||||
|
||||
except Exception as rollback_e:
|
||||
|
||||
|
@ -524,6 +561,20 @@ class HydrusDB( object ):
|
|||
HydrusData.Print( text )
|
||||
|
||||
|
||||
def _Rollback( self ):
|
||||
|
||||
if self._in_transaction:
|
||||
|
||||
self._c.execute( 'ROLLBACK;' )
|
||||
|
||||
self._in_transaction = False
|
||||
|
||||
else:
|
||||
|
||||
HydrusData.Print( 'Received a call to rollback, but was not in a transaction!' )
|
||||
|
||||
|
||||
|
||||
def _SelectFromList( self, select_statement, xs ):
|
||||
|
||||
# issue here is that doing a simple blah_id = ? is real quick and cacheable but doing a lot of fetchone()s is slow
|
||||
|
@ -634,6 +685,8 @@ class HydrusDB( object ):
|
|||
|
||||
self._InitDBCursor() # have to reinitialise because the thread id has changed
|
||||
|
||||
self._InitDiskCache()
|
||||
|
||||
self._InitCaches()
|
||||
|
||||
except:
|
||||
|
|
|
@ -1080,7 +1080,14 @@ def ToUnicode( text_producing_object ):
|
|||
|
||||
except:
|
||||
|
||||
text = repr( text_producing_object )
|
||||
try:
|
||||
|
||||
text = unicode( text_producing_object )
|
||||
|
||||
except:
|
||||
|
||||
text = repr( text_producing_object )
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -135,7 +135,10 @@ def GenerateFilteredRandomBytes( byte_to_exclude, num_bytes ):
|
|||
|
||||
new_byte = os.urandom( 1 )
|
||||
|
||||
if new_byte != byte_to_exclude: bytes.append( new_byte )
|
||||
if new_byte != byte_to_exclude:
|
||||
|
||||
bytes.append( new_byte )
|
||||
|
||||
|
||||
|
||||
return ''.join( bytes )
|
||||
|
@ -149,7 +152,9 @@ def GenerateOpenSSLCertAndKeyFile( cert_path, key_path ):
|
|||
# create a self-signed cert
|
||||
cert = OpenSSL.crypto.X509()
|
||||
|
||||
cert.get_subject().C = 'US'
|
||||
cert.get_subject().countryName = 'HN'
|
||||
cert.get_subject().organizationName = 'hydrus network'
|
||||
cert.get_subject().organizationalUnitName = os.urandom( 32 ).encode( 'hex' )
|
||||
cert.set_serial_number( 1 )
|
||||
cert.gmtime_adj_notBefore( 0 )
|
||||
cert.gmtime_adj_notAfter( 10*365*24*60*60 )
|
||||
|
|
|
@ -199,7 +199,7 @@ def DeletePath( path ):
|
|||
|
||||
except Exception as e:
|
||||
|
||||
if 'Error 32' in str( e ):
|
||||
if 'Error 32' in HydrusData.ToUnicode( e ):
|
||||
|
||||
# file in use by another process
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ class HydrusPubSub( object ):
|
|||
|
||||
except TypeError as e:
|
||||
|
||||
if '_wxPyDeadObject' not in str( e ): raise
|
||||
if '_wxPyDeadObject' not in HydrusData.ToUnicode( e ): raise
|
||||
|
||||
except Exception as e:
|
||||
|
||||
|
|
|
@ -72,7 +72,10 @@ class HydrusRatingArchive( object ):
|
|||
self._c = self._db.cursor()
|
||||
|
||||
|
||||
def BeginBigJob( self ): self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
def BeginBigJob( self ):
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
|
||||
|
||||
def CommitBigJob( self ):
|
||||
|
||||
|
@ -123,7 +126,10 @@ class HydrusRatingArchive( object ):
|
|||
|
||||
filename = os.path.basename( self._path )
|
||||
|
||||
if '.' in filename: filename = filename.split( '.', 1 )[0]
|
||||
if '.' in filename:
|
||||
|
||||
filename = filename.split( '.', 1 )[0]
|
||||
|
||||
|
||||
return filename
|
||||
|
||||
|
|
|
@ -136,7 +136,10 @@ class HydrusTagArchive( object ):
|
|||
return tag_id
|
||||
|
||||
|
||||
def BeginBigJob( self ): self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
def BeginBigJob( self ):
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
|
||||
|
||||
def CommitBigJob( self ):
|
||||
|
||||
|
@ -222,7 +225,10 @@ class HydrusTagArchive( object ):
|
|||
|
||||
filename = os.path.basename( self._path )
|
||||
|
||||
if '.' in filename: filename = filename.split( '.', 1 )[0]
|
||||
if '.' in filename:
|
||||
|
||||
filename = filename.split( '.', 1 )[0]
|
||||
|
||||
|
||||
return filename
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ def CleanTag( tag ):
|
|||
|
||||
text = 'Was unable to parse the tag: ' + HydrusData.ToUnicode( tag )
|
||||
text += os.linesep * 2
|
||||
text += str( e )
|
||||
text += HydrusData.ToUnicode( e )
|
||||
|
||||
raise Exception( text )
|
||||
|
||||
|
|
|
@ -270,7 +270,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
def _Backup( self ):
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._CloseDBCursor()
|
||||
|
||||
|
@ -325,7 +325,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._InitDBCursor()
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
|
||||
HydrusData.Print( 'backing up: done!' )
|
||||
|
@ -344,7 +344,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
HydrusDB.SetupDBCreatePragma( self._c, no_wal = self._no_wal )
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE' )
|
||||
self._BeginImmediate()
|
||||
|
||||
self._c.execute( 'CREATE TABLE services ( service_id INTEGER PRIMARY KEY, service_key BLOB_BYTES, service_type INTEGER, name TEXT, port INTEGER, dictionary_string TEXT );' )
|
||||
|
||||
|
@ -393,7 +393,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._AddService( admin_service ) # this sets up the admin account and a registration key by itself
|
||||
|
||||
self._c.execute( 'COMMIT' )
|
||||
self._Commit()
|
||||
|
||||
|
||||
def _DeleteOrphans( self ):
|
||||
|
@ -510,6 +510,17 @@ class DB( HydrusDB.HydrusDB ):
|
|||
return self._GetAccount( service_id, account_id )
|
||||
|
||||
|
||||
def _GetAccountFromAccountKeyAdmin( self, admin_account, service_key, account_key ):
|
||||
|
||||
# check admin account
|
||||
|
||||
service_id = self._GetServiceId( service_key )
|
||||
|
||||
account_id = self._GetAccountId( account_key )
|
||||
|
||||
return self._GetAccount( service_id, account_id )
|
||||
|
||||
|
||||
def _GetAccountKeyFromAccessKey( self, service_key, access_key ):
|
||||
|
||||
service_id = self._GetServiceId( service_key )
|
||||
|
@ -565,31 +576,103 @@ class DB( HydrusDB.HydrusDB ):
|
|||
return account_key
|
||||
|
||||
|
||||
def _GetAccountKeyFromIdentifier( self, service_id, account_identifier ):
|
||||
def _GetAccountFromContent( self, admin_account, service_key, content ):
|
||||
|
||||
if account_identifier.HasAccountKey():
|
||||
# check admin account
|
||||
|
||||
service_id = self._GetServiceId( service_key )
|
||||
|
||||
content_type = content.GetContentType()
|
||||
content_data = content.GetContentData()
|
||||
|
||||
if content_type == HC.CONTENT_TYPE_FILES:
|
||||
|
||||
account_key = account_identifier.GetData()
|
||||
hash = content_data[0]
|
||||
|
||||
result = self._c.execute( 'SELECT 1 FROM accounts WHERE service_id = ? AND account_key = ?;', ( service_id, sqlite3.Binary( account_key ) ) ).fetchone()
|
||||
|
||||
if result is None: raise HydrusExceptions.ForbiddenException( 'The service could not find that hash in its database.')
|
||||
|
||||
elif account_identifier.HasContent():
|
||||
|
||||
account_id = self._RepositoryGetAccountIdFromAccountIdentifierContent( service_id, account_identifier )
|
||||
|
||||
try:
|
||||
if not self._MasterHashExists( hash ):
|
||||
|
||||
( account_key, ) = self._c.execute( 'SELECT account_key FROM accounts WHERE account_id = ?;', ( account_id, ) ).fetchone()
|
||||
raise HydrusExceptions.NotFoundException( 'The service could not find that hash in its database.' )
|
||||
|
||||
except:
|
||||
|
||||
master_hash_id = self._GetMasterHashId( hash )
|
||||
|
||||
if not self._RepositoryServiceHashIdExists( service_id, master_hash_id ):
|
||||
|
||||
raise HydrusExceptions.NotFoundException( 'The service could not find that account in its database.' )
|
||||
raise HydrusExceptions.NotFoundException( 'The service could not find that service hash in its database.' )
|
||||
|
||||
|
||||
service_hash_id = self._RepositoryGetServiceHashId( service_id, master_hash_id )
|
||||
|
||||
( current_files_table_name, deleted_files_table_name, pending_files_table_name, petitioned_files_table_name, ip_addresses_table_name ) = GenerateRepositoryFilesTableNames( service_id )
|
||||
|
||||
result = self._c.execute( 'SELECT account_id FROM ' + current_files_table_name + ' WHERE service_hash_id = ?;', ( service_hash_id, ) ).fetchone()
|
||||
|
||||
if result is None:
|
||||
|
||||
result = self._c.execute( 'SELECT account_id FROM ' + deleted_files_table_name + ' WHERE service_hash_id = ?;', ( service_hash_id, ) ).fetchone()
|
||||
|
||||
|
||||
if result is None:
|
||||
|
||||
raise HydrusExceptions.NotFoundException( 'The service could not find that hash in its database.' )
|
||||
|
||||
|
||||
elif content_type == HC.CONTENT_TYPE_MAPPING:
|
||||
|
||||
( tag, hash ) = content_data
|
||||
|
||||
if not self._MasterHashExists( hash ):
|
||||
|
||||
raise HydrusExceptions.NotFoundException( 'The service could not find that hash in its database.' )
|
||||
|
||||
|
||||
master_hash_id = self._GetMasterHashId( hash )
|
||||
|
||||
if not self._RepositoryServiceHashIdExists( service_id, master_hash_id ):
|
||||
|
||||
raise HydrusExceptions.NotFoundException( 'The service could not find that service hash in its database.' )
|
||||
|
||||
|
||||
service_hash_id = self._RepositoryGetServiceHashId( service_id, master_hash_id )
|
||||
|
||||
if not self._MasterTagExists( tag ):
|
||||
|
||||
raise HydrusExceptions.NotFoundException( 'The service could not find that tag in its database.' )
|
||||
|
||||
|
||||
master_tag_id = self._GetMasterTagId( tag )
|
||||
|
||||
if not self._RepositoryServiceTagIdExists( service_id, master_tag_id ):
|
||||
|
||||
raise HydrusExceptions.NotFoundException( 'The service could not find that service tag in its database.' )
|
||||
|
||||
|
||||
service_tag_id = self._RepositoryGetServiceTagId( service_id, master_tag_id )
|
||||
|
||||
( current_mappings_table_name, deleted_mappings_table_name, pending_mappings_table_name, petitioned_mappings_table_name ) = GenerateRepositoryMappingsTableNames( service_id )
|
||||
|
||||
result = self._c.execute( 'SELECT account_id FROM ' + current_mappings_table_name + ' WHERE service_tag_id = ? AND service_hash_id = ?;', ( service_tag_id, service_hash_id ) ).fetchone()
|
||||
|
||||
if result is None:
|
||||
|
||||
result = self._c.execute( 'SELECT account_id FROM ' + deleted_mappings_table_name + ' WHERE service_tag_id = ? AND service_hash_id = ?;', ( service_tag_id, service_hash_id ) ).fetchone()
|
||||
|
||||
|
||||
if result is None:
|
||||
|
||||
raise HydrusExceptions.NotFoundException( 'The service could not find that mapping in its database.' )
|
||||
|
||||
|
||||
else:
|
||||
|
||||
raise HydrusExceptions.NotFoundException( 'The service could not understand the submitted content.' )
|
||||
|
||||
|
||||
return account_key
|
||||
( account_id, ) = result
|
||||
|
||||
account = self._GetAccount( service_id, account_id )
|
||||
|
||||
return account
|
||||
|
||||
|
||||
def _GetAccountId( self, account_key ):
|
||||
|
@ -603,18 +686,16 @@ class DB( HydrusDB.HydrusDB ):
|
|||
return account_id
|
||||
|
||||
|
||||
def _GetAccountInfo( self, service_key, account, subject_account_identifier ):
|
||||
def _GetAccountInfo( self, service_key, account, subject_account ):
|
||||
|
||||
account.CheckPermission( HC.CONTENT_TYPE_ACCOUNTS, HC.PERMISSION_ACTION_OVERRULE )
|
||||
|
||||
service_id = self._GetServiceId( service_key )
|
||||
|
||||
subject_account_key = self._GetAccountKeyFromIdentifier( service_id, subject_account_identifier )
|
||||
subject_account_key = subject_account.GetAccountKey()
|
||||
|
||||
subject_account_id = self._GetAccountId( subject_account_key )
|
||||
|
||||
subject_account = self._GetAccount( service_id, subject_account_id )
|
||||
|
||||
service_type = self._GetServiceType( service_id )
|
||||
|
||||
if service_type in HC.REPOSITORIES:
|
||||
|
@ -626,8 +707,6 @@ class DB( HydrusDB.HydrusDB ):
|
|||
account_info = {}
|
||||
|
||||
|
||||
account_info[ 'account' ] = HydrusNetwork.Account.GenerateSerialisableTupleFromAccount( subject_account )
|
||||
|
||||
return account_info
|
||||
|
||||
|
||||
|
@ -1123,7 +1202,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
account.CheckPermission( HC.CONTENT_TYPE_SERVICES, HC.PERMISSION_ACTION_OVERRULE )
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
if not self._fast_big_transaction_wal:
|
||||
|
||||
|
@ -1132,7 +1211,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._c.execute( 'PRAGMA foreign_keys = ON;' )
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
current_service_keys = { service_key for ( service_key, ) in self._c.execute( 'SELECT service_key FROM services;' ) }
|
||||
|
||||
|
@ -1170,11 +1249,11 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._InitDBCursor()
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
return service_keys_to_access_keys
|
||||
|
||||
|
@ -1805,107 +1884,6 @@ class DB( HydrusDB.HydrusDB ):
|
|||
return updates
|
||||
|
||||
|
||||
def _RepositoryGetAccountIdFromAccountIdentifierContent( self, service_id, account_identifier ):
|
||||
|
||||
content = account_identifier.GetData()
|
||||
|
||||
content_type = content.GetContentType()
|
||||
content_data = content.GetContentData()
|
||||
|
||||
if content_type == HC.CONTENT_TYPE_FILES:
|
||||
|
||||
try:
|
||||
|
||||
hash = content_data[0]
|
||||
|
||||
if not self._MasterHashExists( hash ):
|
||||
|
||||
raise Exception()
|
||||
|
||||
|
||||
master_hash_id = self._GetMasterHashId( hash )
|
||||
|
||||
if not self._RepositoryServiceHashIdExists( service_id, master_hash_id ):
|
||||
|
||||
raise Exception()
|
||||
|
||||
|
||||
service_hash_id = self._RepositoryGetServiceHashId( service_id, master_hash_id )
|
||||
|
||||
( current_files_table_name, deleted_files_table_name, pending_files_table_name, petitioned_files_table_name, ip_addresses_table_name ) = GenerateRepositoryFilesTableNames( service_id )
|
||||
|
||||
result = self._c.execute( 'SELECT account_id FROM ' + current_files_table_name + ' WHERE service_hash_id = ?;', ( service_hash_id, ) ).fetchone()
|
||||
|
||||
if result is None:
|
||||
|
||||
result = self._c.execute( 'SELECT account_id FROM ' + deleted_files_table_name + ' WHERE service_hash_id = ?;', ( service_hash_id, ) ).fetchone()
|
||||
|
||||
|
||||
( account_id, ) = result
|
||||
|
||||
return account_id
|
||||
|
||||
except:
|
||||
|
||||
raise HydrusExceptions.NotFoundException( 'The service could not find that hash in its database.' )
|
||||
|
||||
|
||||
elif content_type == HC.CONTENT_TYPE_MAPPING:
|
||||
|
||||
try:
|
||||
|
||||
( tag, hash ) = content_data
|
||||
|
||||
if not self._MasterHashExists( hash ):
|
||||
|
||||
raise Exception()
|
||||
|
||||
|
||||
master_hash_id = self._GetMasterHashId( hash )
|
||||
|
||||
if not self._RepositoryServiceHashIdExists( service_id, master_hash_id ):
|
||||
|
||||
raise Exception()
|
||||
|
||||
|
||||
service_hash_id = self._RepositoryGetServiceHashId( service_id, master_hash_id )
|
||||
|
||||
if not self._MasterTagExists( tag ):
|
||||
|
||||
raise Exception()
|
||||
|
||||
|
||||
master_tag_id = self._GetMasterTagId( tag )
|
||||
|
||||
if not self._RepositoryServiceTagIdExists( service_id, master_tag_id ):
|
||||
|
||||
raise Exception()
|
||||
|
||||
|
||||
service_tag_id = self._RepositoryGetServiceTagId( service_id, master_tag_id )
|
||||
|
||||
( current_mappings_table_name, deleted_mappings_table_name, pending_mappings_table_name, petitioned_mappings_table_name ) = GenerateRepositoryMappingsTableNames( service_id )
|
||||
|
||||
result = self._c.execute( 'SELECT account_id FROM ' + current_mappings_table_name + ' WHERE service_tag_id = ? AND service_hash_id = ?;', ( service_tag_id, service_hash_id ) ).fetchone()
|
||||
|
||||
if result is None:
|
||||
|
||||
result = self._c.execute( 'SELECT account_id FROM ' + deleted_mappings_table_name + ' WHERE service_tag_id = ? AND service_hash_id = ?;', ( service_tag_id, service_hash_id ) ).fetchone()
|
||||
|
||||
|
||||
( account_id, ) = result
|
||||
|
||||
return account_id
|
||||
|
||||
except:
|
||||
|
||||
raise HydrusExceptions.NotFoundException( 'The service could not find that mapping in its database.' )
|
||||
|
||||
|
||||
|
||||
raise HydrusExceptions.NotFoundException( 'The service could not understand that account identifier.' )
|
||||
|
||||
|
||||
def _RepositoryGetAccountInfo( self, service_id, account_id ):
|
||||
|
||||
( hash_id_map_table_name, tag_id_map_table_name ) = GenerateRepositoryMasterMapTableNames( service_id )
|
||||
|
@ -3199,7 +3177,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
#
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._CloseDBCursor()
|
||||
|
||||
|
@ -3221,7 +3199,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._InitDBCursor()
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
|
||||
|
||||
|
@ -3357,11 +3335,11 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
if foreign_keys_on:
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._c.execute( 'PRAGMA foreign_keys = ?;', ( False, ) )
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
|
||||
HydrusData.Print( 'updating services' )
|
||||
|
@ -3924,7 +3902,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
HydrusData.Print( 'committing to disk' )
|
||||
|
||||
self._c.execute( 'COMMIT;' )
|
||||
self._Commit()
|
||||
|
||||
self._CloseDBCursor()
|
||||
|
||||
|
@ -3954,7 +3932,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._InitDBCursor()
|
||||
|
||||
self._c.execute( 'BEGIN IMMEDIATE;' )
|
||||
self._BeginImmediate()
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -144,6 +144,11 @@ class TestListBoxes( unittest.TestCase ):
|
|||
|
||||
random_index = random.choice( all_clickable_indices.keys() )
|
||||
|
||||
while ordered_terms[ random_index ][0] in panel.PROTECTED_TERMS:
|
||||
|
||||
random_index = random.choice( all_clickable_indices.keys() )
|
||||
|
||||
|
||||
del new_namespace_colours[ ordered_terms[ random_index ][0] ]
|
||||
|
||||
# select nothing
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import ClientConstants as CC
|
||||
import ClientData
|
||||
import ClientDownloading
|
||||
import ClientImporting
|
||||
import ClientSearch
|
||||
import HydrusConstants as HC
|
||||
import HydrusData
|
||||
|
@ -9,7 +11,7 @@ import os
|
|||
import unittest
|
||||
import wx
|
||||
|
||||
class TestServer( unittest.TestCase ):
|
||||
class TestSerialisables( unittest.TestCase ):
|
||||
|
||||
def _dump_and_load_and_test( self, obj, test_func ):
|
||||
|
||||
|
@ -163,3 +165,68 @@ class TestServer( unittest.TestCase ):
|
|||
self.assertEqual( shortcuts.GetMouseAction( modifier, mouse_button ), action )
|
||||
|
||||
|
||||
|
||||
def test_SERIALISABLE_TYPE_SUBSCRIPTION( self ):
|
||||
|
||||
def test( obj, dupe_obj ):
|
||||
|
||||
self.assertEqual( obj.GetName(), dupe_obj.GetName() )
|
||||
|
||||
self.assertEqual( obj._gallery_identifier, dupe_obj._gallery_identifier )
|
||||
self.assertEqual( obj._gallery_stream_identifiers, dupe_obj._gallery_stream_identifiers )
|
||||
self.assertEqual( obj._query, dupe_obj._query )
|
||||
self.assertEqual( obj._period, dupe_obj._period )
|
||||
self.assertEqual( obj._get_tags_if_url_known_and_file_redundant, dupe_obj._get_tags_if_url_known_and_file_redundant )
|
||||
self.assertEqual( obj._initial_file_limit, dupe_obj._initial_file_limit )
|
||||
self.assertEqual( obj._periodic_file_limit, dupe_obj._periodic_file_limit )
|
||||
self.assertEqual( obj._paused, dupe_obj._paused )
|
||||
|
||||
self.assertEqual( obj._import_file_options.GetSerialisableTuple(), dupe_obj._import_file_options.GetSerialisableTuple() )
|
||||
self.assertEqual( obj._import_tag_options.GetSerialisableTuple(), dupe_obj._import_tag_options.GetSerialisableTuple() )
|
||||
|
||||
self.assertEqual( obj._last_checked, dupe_obj._last_checked )
|
||||
self.assertEqual( obj._last_error, dupe_obj._last_error )
|
||||
self.assertEqual( obj._check_now, dupe_obj._check_now )
|
||||
|
||||
self.assertEqual( obj._seed_cache.GetSerialisableTuple(), dupe_obj._seed_cache.GetSerialisableTuple() )
|
||||
|
||||
|
||||
sub = ClientImporting.Subscription( 'test sub' )
|
||||
|
||||
self._dump_and_load_and_test( sub, test )
|
||||
|
||||
gallery_identifier = ClientDownloading.GalleryIdentifier( HC.SITE_TYPE_BOORU, 'gelbooru' )
|
||||
gallery_stream_identifiers = ClientDownloading.GetGalleryStreamIdentifiers( gallery_identifier )
|
||||
query = 'test query'
|
||||
period = 86400 * 7
|
||||
get_tags_if_url_known_and_file_redundant = True
|
||||
initial_file_limit = 100
|
||||
periodic_file_limit = 50
|
||||
paused = False
|
||||
|
||||
import_file_options = ClientData.ImportFileOptions( automatic_archive = False, exclude_deleted = True, min_size = 8 * 1024, min_resolution = [ 25, 25 ] )
|
||||
import_tag_options = ClientData.ImportTagOptions( service_keys_to_namespaces = { HydrusData.GenerateKey() : { 'series', '' } }, service_keys_to_explicit_tags = { HydrusData.GenerateKey() : { 'test explicit tag', 'and another' } } )
|
||||
|
||||
last_checked = HydrusData.GetNow() - 3600
|
||||
last_error = HydrusData.GetNow() - 86400 * 20
|
||||
check_now = False
|
||||
seed_cache = ClientImporting.SeedCache()
|
||||
|
||||
seed_cache.AddSeed( 'http://exampleurl.com/image/123456' )
|
||||
|
||||
sub.SetTuple( gallery_identifier, gallery_stream_identifiers, query, period, get_tags_if_url_known_and_file_redundant, initial_file_limit, periodic_file_limit, paused, import_file_options, import_tag_options, last_checked, last_error, check_now, seed_cache )
|
||||
|
||||
self.assertEqual( sub.GetGalleryIdentifier(), gallery_identifier )
|
||||
self.assertEqual( sub.GetImportTagOptions(), import_tag_options )
|
||||
self.assertEqual( sub.GetQuery(), query )
|
||||
self.assertEqual( sub.GetSeedCache(), seed_cache )
|
||||
|
||||
self.assertEqual( sub._paused, False )
|
||||
sub.PauseResume()
|
||||
self.assertEqual( sub._paused, True )
|
||||
sub.PauseResume()
|
||||
self.assertEqual( sub._paused, False )
|
||||
|
||||
self._dump_and_load_and_test( sub, test )
|
||||
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import HydrusServerResources
|
|||
import HydrusSerialisable
|
||||
import itertools
|
||||
import os
|
||||
import random
|
||||
import ServerFiles
|
||||
import ServerServer
|
||||
import shutil
|
||||
|
@ -46,17 +47,25 @@ class TestServer( unittest.TestCase ):
|
|||
|
||||
services = []
|
||||
|
||||
self._file_service = HydrusNetwork.GenerateService( HydrusData.GenerateKey(), HC.FILE_REPOSITORY, 'file repo', HC.DEFAULT_SERVICE_PORT + 1 )
|
||||
self._tag_service = HydrusNetwork.GenerateService( HydrusData.GenerateKey(), HC.TAG_REPOSITORY, 'tag repo', HC.DEFAULT_SERVICE_PORT )
|
||||
self._admin_service = HydrusNetwork.GenerateService( HydrusData.GenerateKey(), HC.SERVER_ADMIN, 'server admin', HC.DEFAULT_SERVER_ADMIN_PORT )
|
||||
self._serverside_file_service = HydrusNetwork.GenerateService( HydrusData.GenerateKey(), HC.FILE_REPOSITORY, 'file repo', HC.DEFAULT_SERVICE_PORT + 1 )
|
||||
self._serverside_tag_service = HydrusNetwork.GenerateService( HydrusData.GenerateKey(), HC.TAG_REPOSITORY, 'tag repo', HC.DEFAULT_SERVICE_PORT )
|
||||
self._serverside_admin_service = HydrusNetwork.GenerateService( HydrusData.GenerateKey(), HC.SERVER_ADMIN, 'server admin', HC.DEFAULT_SERVER_ADMIN_PORT )
|
||||
|
||||
self._clientside_file_service = ClientServices.GenerateService( HydrusData.GenerateKey(), HC.FILE_REPOSITORY, 'file repo' )
|
||||
self._clientside_tag_service = ClientServices.GenerateService( HydrusData.GenerateKey(), HC.TAG_REPOSITORY, 'tag repo' )
|
||||
self._clientside_admin_service = ClientServices.GenerateService( HydrusData.GenerateKey(), HC.SERVER_ADMIN, 'server admin' )
|
||||
|
||||
self._clientside_file_service.SetCredentials( HydrusNetwork.Credentials( '127.0.0.1', HC.DEFAULT_SERVICE_PORT + 1 ) )
|
||||
self._clientside_tag_service.SetCredentials( HydrusNetwork.Credentials( '127.0.0.1', HC.DEFAULT_SERVICE_PORT ) )
|
||||
self._clientside_admin_service.SetCredentials( HydrusNetwork.Credentials( '127.0.0.1', HC.DEFAULT_SERVER_ADMIN_PORT ) )
|
||||
|
||||
self._local_booru = ClientServices.GenerateService( HydrusData.GenerateKey(), HC.LOCAL_BOORU, 'local booru' )
|
||||
|
||||
services_manager = HydrusGlobals.test_controller.GetServicesManager()
|
||||
|
||||
services_manager._keys_to_services[ self._file_service.GetServiceKey() ] = self._file_service
|
||||
services_manager._keys_to_services[ self._tag_service.GetServiceKey() ] = self._tag_service
|
||||
services_manager._keys_to_services[ self._admin_service.GetServiceKey() ] = self._admin_service
|
||||
services_manager._keys_to_services[ self._clientside_file_service.GetServiceKey() ] = self._clientside_file_service
|
||||
services_manager._keys_to_services[ self._clientside_tag_service.GetServiceKey() ] = self._clientside_tag_service
|
||||
services_manager._keys_to_services[ self._clientside_admin_service.GetServiceKey() ] = self._clientside_admin_service
|
||||
|
||||
permissions = [ HC.GET_DATA, HC.POST_DATA, HC.POST_PETITIONS, HC.RESOLVE_PETITIONS, HC.MANAGE_USERS, HC.GENERAL_ADMIN, HC.EDIT_SERVICES ]
|
||||
|
||||
|
@ -85,9 +94,9 @@ class TestServer( unittest.TestCase ):
|
|||
|
||||
context_factory = twisted.internet.ssl.DefaultOpenSSLContextFactory( self._ssl_key_path, self._ssl_cert_path )
|
||||
|
||||
reactor.listenSSL( HC.DEFAULT_SERVER_ADMIN_PORT, ServerServer.HydrusServiceAdmin( self._admin_service ), context_factory )
|
||||
reactor.listenSSL( HC.DEFAULT_SERVICE_PORT, ServerServer.HydrusServiceRepositoryFile( self._file_service ), context_factory )
|
||||
reactor.listenSSL( HC.DEFAULT_SERVICE_PORT + 1, ServerServer.HydrusServiceRepositoryTag( self._tag_service ), context_factory )
|
||||
reactor.listenSSL( HC.DEFAULT_SERVER_ADMIN_PORT, ServerServer.HydrusServiceAdmin( self._serverside_admin_service ), context_factory )
|
||||
reactor.listenSSL( HC.DEFAULT_SERVICE_PORT, ServerServer.HydrusServiceRepositoryFile( self._serverside_file_service ), context_factory )
|
||||
reactor.listenSSL( HC.DEFAULT_SERVICE_PORT + 1, ServerServer.HydrusServiceRepositoryTag( self._serverside_tag_service ), context_factory )
|
||||
|
||||
reactor.listenTCP( HC.DEFAULT_LOCAL_BOORU_PORT, ClientLocalServer.HydrusServiceBooru( self._local_booru ) )
|
||||
|
||||
|
@ -120,10 +129,7 @@ class TestServer( unittest.TestCase ):
|
|||
|
||||
data = response.read()
|
||||
|
||||
p1 = data == HydrusServerResources.CLIENT_ROOT_MESSAGE
|
||||
p2 = data == HydrusServerResources.ROOT_MESSAGE_BEGIN + 'hello' + HydrusServerResources.ROOT_MESSAGE_END
|
||||
|
||||
self.assertTrue( p1 or p2 )
|
||||
self.assertEqual( response.status, 200 )
|
||||
|
||||
#
|
||||
|
||||
|
@ -138,7 +144,7 @@ class TestServer( unittest.TestCase ):
|
|||
self.assertEqual( data, favicon )
|
||||
|
||||
|
||||
def _test_file_repo( self, service, host, port ):
|
||||
def _test_file_repo( self, service ):
|
||||
|
||||
info = service.GetInfo()
|
||||
|
||||
|
@ -314,13 +320,13 @@ class TestServer( unittest.TestCase ):
|
|||
|
||||
|
||||
|
||||
def _test_repo( self, service, host, port ):
|
||||
def _test_repo( self, service ):
|
||||
|
||||
service_key = service.GetServiceKey()
|
||||
|
||||
# num_petitions
|
||||
|
||||
num_petitions = 23
|
||||
num_petitions = [ ( HC.CONTENT_TYPE_MAPPINGS, HC.CONTENT_STATUS_PETITIONED, 23 ), ( HC.CONTENT_TYPE_TAG_PARENTS, HC.CONTENT_STATUS_PENDING, 0 ) ]
|
||||
|
||||
HydrusGlobals.test_controller.SetRead( 'num_petitions', num_petitions )
|
||||
|
||||
|
@ -331,58 +337,83 @@ class TestServer( unittest.TestCase ):
|
|||
# petition
|
||||
|
||||
action = HC.CONTENT_UPDATE_PETITION
|
||||
account_identifier = HydrusData.AccountIdentifier( account_key = HydrusData.GenerateKey() )
|
||||
petitioner_account = HydrusNetwork.Account.GenerateUnknownAccount()
|
||||
reason = 'it sucks'
|
||||
contents = [ HydrusNetwork.Content( HC.CONTENT_TYPE_FILES, [ HydrusData.GenerateKey() for i in range( 10 ) ] ) ]
|
||||
|
||||
petition = HydrusData.ServerToClientPetition( action = action, petitioner_account_identifier = account_identifier, reason = reason, contents = contents )
|
||||
petition = HydrusNetwork.Petition( action, petitioner_account, reason, contents )
|
||||
|
||||
HydrusGlobals.test_controller.SetRead( 'petition', petition )
|
||||
|
||||
response = service.Request( HC.GET, 'petition' )
|
||||
|
||||
self.assertEqual( type( response ), HydrusData.ServerToClientPetition )
|
||||
self.assertEqual( response[ 'petition' ].GetSerialisableTuple(), petition.GetSerialisableTuple() )
|
||||
|
||||
# update
|
||||
# definitions
|
||||
|
||||
begin = 100
|
||||
subindex_count = 5
|
||||
definitions_update = HydrusNetwork.DefinitionsUpdate()
|
||||
|
||||
update = HydrusData.ServerToClientServiceUpdatePackage()
|
||||
update.SetBeginEnd( begin, begin + HC.UPDATE_DURATION - 1 )
|
||||
update.SetSubindexCount( subindex_count )
|
||||
if i in range( 100, 200 ):
|
||||
|
||||
definitions_update.AddRow( ( HC.DEFINITIONS_TYPE_TAGS, i, 'series:test ' + str( i ) ) )
|
||||
definitions_update.AddRow( ( HC.DEFINITIONS_TYPE_HASHES, i + 500, HydrusData.GenerateKey() ) )
|
||||
|
||||
|
||||
path = ServerFiles.GetFilePath( hash )
|
||||
definitions_update_network_string = definitions_update.DumpToNetworkString()
|
||||
|
||||
with open( path, 'wb' ) as f: f.write( update.DumpToNetworkString() )
|
||||
definitions_update_hash = hashlib.sha256( definitions_update_network_string ).digest()
|
||||
|
||||
response = service.Request( HC.GET, 'service_update_package', { 'begin' : begin } )
|
||||
path = ServerFiles.GetExpectedFilePath( definitions_update_hash )
|
||||
|
||||
self.assertEqual( response.GetBegin(), update.GetBegin() )
|
||||
with open( path, 'wb' ) as f: f.write( definitions_update_network_string )
|
||||
|
||||
response = service.Request( HC.GET, 'update', { 'update_hash' : definitions_update_hash } )
|
||||
|
||||
try: os.remove( path )
|
||||
except: pass
|
||||
|
||||
subindex = 2
|
||||
num_hashes = 12
|
||||
tag = 'series:blah'
|
||||
hash_ids_to_hashes = { i : HydrusData.GenerateKey() for i in range( 12 ) }
|
||||
rows = [ ( tag, [ i for i in range( num_hashes ) ] ) ]
|
||||
self.assertEqual( response, definitions_update_network_string )
|
||||
|
||||
update = HydrusData.ServerToClientContentUpdatePackage()
|
||||
update.AddContentData( HC.CONTENT_TYPE_MAPPINGS, HC.CONTENT_UPDATE_ADD, rows, hash_ids_to_hashes )
|
||||
# content
|
||||
|
||||
path = ServerFiles.GetExpectedContentUpdatePackagePath( service_key, begin, subindex )
|
||||
rows = [ ( random.randint( 100, 1000 ), [ random.randint( 100, 1000 ) for i in range( 50 ) ] ) for j in range( 20 ) ]
|
||||
|
||||
with open( path, 'wb' ) as f: f.write( update.DumpToNetworkString() )
|
||||
content_update = HydrusNetwork.ContentUpdate()
|
||||
|
||||
response = service.Request( HC.GET, 'content_update_package', { 'begin' : begin, 'subindex' : subindex } )
|
||||
for row in rows:
|
||||
|
||||
content_update.AddRow( ( HC.CONTENT_TYPE_MAPPINGS, HC.CONTENT_UPDATE_ADD, row ) )
|
||||
|
||||
|
||||
raise Exception( 'change this to numrows or whatever' )
|
||||
content_update_network_string = content_update.DumpToNetworkString()
|
||||
|
||||
content_update_hash = hashlib.sha256( content_update_network_string ).digest()
|
||||
|
||||
path = ServerFiles.GetExpectedFilePath( content_update_hash )
|
||||
|
||||
with open( path, 'wb' ) as f: f.write( content_update_network_string )
|
||||
|
||||
response = service.Request( HC.GET, 'update', { 'update_hash' : content_update_hash } )
|
||||
|
||||
try: os.remove( path )
|
||||
except: pass
|
||||
|
||||
self.assertEqual( response, content_update_network_string )
|
||||
|
||||
# metadata
|
||||
|
||||
metadata = HydrusNetwork.Metadata()
|
||||
|
||||
metadata.AppendUpdate( [ definitions_update_hash, content_update_hash ], HydrusData.GetNow() - 101000, HydrusData.GetNow() - 1000, HydrusData.GetNow() + 100000 )
|
||||
|
||||
service._metadata = metadata
|
||||
|
||||
response = service.Request( HC.GET, 'metadata_slice', { 'since' : 0 } )
|
||||
|
||||
self.assertEqual( response[ 'metadata_slice' ].GetSerialisableTuple(), metadata.GetSerialisableTuple() )
|
||||
|
||||
# post content
|
||||
|
||||
update = HydrusData.ClientToServerContentUpdatePackage( {}, hash_ids_to_hashes )
|
||||
|
||||
service.Request( HC.POST, 'content_update_package', { 'update' : update } )
|
||||
|
@ -396,7 +427,7 @@ class TestServer( unittest.TestCase ):
|
|||
self.assertEqual( update.GetHashes(), written_update.GetHashes() )
|
||||
|
||||
|
||||
def _test_restricted( self, service, host, port ):
|
||||
def _test_restricted( self, service ):
|
||||
|
||||
# access_key
|
||||
|
||||
|
@ -481,12 +512,7 @@ class TestServer( unittest.TestCase ):
|
|||
self.assertEqual( response[ 'registration_keys' ], [ registration_key ] )
|
||||
|
||||
|
||||
def _test_server_admin( self, service, host, port ):
|
||||
|
||||
info = service.GetInfo()
|
||||
|
||||
info[ 'host' ] = host
|
||||
info[ 'port' ] = port
|
||||
def _test_server_admin( self, service ):
|
||||
|
||||
# init
|
||||
|
||||
|
@ -500,8 +526,6 @@ class TestServer( unittest.TestCase ):
|
|||
|
||||
#
|
||||
|
||||
info[ 'access_key' ] = self._access_key
|
||||
|
||||
# backup
|
||||
|
||||
response = service.Request( HC.POST, 'backup' )
|
||||
|
@ -529,7 +553,7 @@ class TestServer( unittest.TestCase ):
|
|||
self.assertEqual( edit_log, written_edit_log )
|
||||
|
||||
|
||||
def _test_tag_repo( self, service, host, port ):
|
||||
def _test_tag_repo( self, service ):
|
||||
|
||||
pass
|
||||
|
||||
|
@ -539,15 +563,10 @@ class TestServer( unittest.TestCase ):
|
|||
host = '127.0.0.1'
|
||||
port = HC.DEFAULT_SERVICE_PORT
|
||||
|
||||
info = self._file_service.GetInfo()
|
||||
|
||||
info[ 'host' ] = host
|
||||
info[ 'port' ] = port
|
||||
|
||||
self._test_basics( host, port )
|
||||
self._test_restricted( self._file_service, host, port )
|
||||
self._test_repo( self._file_service, host, port )
|
||||
self._test_file_repo( self._file_service, host, port )
|
||||
self._test_restricted( self._clientside_file_service )
|
||||
self._test_repo( self._clientside_file_service )
|
||||
self._test_file_repo( self._clientside_file_service )
|
||||
|
||||
|
||||
def test_repository_tag( self ):
|
||||
|
@ -555,15 +574,10 @@ class TestServer( unittest.TestCase ):
|
|||
host = '127.0.0.1'
|
||||
port = HC.DEFAULT_SERVICE_PORT + 1
|
||||
|
||||
info = self._tag_service.GetInfo()
|
||||
|
||||
info[ 'host' ] = host
|
||||
info[ 'port' ] = port
|
||||
|
||||
self._test_basics( host, port )
|
||||
self._test_restricted( self._tag_service, host, port )
|
||||
self._test_repo( self._tag_service, host, port )
|
||||
self._test_tag_repo( self._tag_service, host, port )
|
||||
self._test_restricted( self._clientside_tag_service )
|
||||
self._test_repo( self._clientside_tag_service )
|
||||
self._test_tag_repo( self._clientside_tag_service )
|
||||
|
||||
|
||||
def test_server_admin( self ):
|
||||
|
@ -571,14 +585,9 @@ class TestServer( unittest.TestCase ):
|
|||
host = '127.0.0.1'
|
||||
port = HC.DEFAULT_SERVER_ADMIN_PORT
|
||||
|
||||
info = self._admin_service.GetInfo()
|
||||
|
||||
info[ 'host' ] = host
|
||||
info[ 'port' ] = port
|
||||
|
||||
self._test_basics( host, port )
|
||||
self._test_restricted( self._admin_service, host, port )
|
||||
self._test_server_admin( self._admin_service, host, port )
|
||||
self._test_restricted( self._clientside_admin_service )
|
||||
self._test_server_admin( self._clientside_admin_service )
|
||||
|
||||
|
||||
def test_local_booru( self ):
|
||||
|
|
Loading…
Reference in New Issue