Version 72

This commit is contained in:
Hydrus 2013-06-12 17:53:31 -05:00
parent 849ccb68db
commit 00ea2d6096
15 changed files with 2975 additions and 2279 deletions

View File

@ -12,7 +12,7 @@
<ul>
<li>collapsed the four mappings tables into two tables</li>
<li>merged the two active_mappings tables into the mappings table</li>
<li>made a _great_ number of changes to how mappings and active_mappings are stored and processed throughout</li>
<li>made a <i>great</i> number of changes to how mappings and active_mappings are stored and processed throughout</li>
<li>'active' and 'null' nomenclature is now 'combined'; null service_ids are now just ints</li>
<li>improved deletepending so it isn't so tough on the a/c cache</li>
<li>tags regex dialog entries 'for all files' and 'just for this file' was all broke</li>

View File

@ -175,8 +175,6 @@ sort_string_lookup[ SORT_BY_RANDOM ] = 'random order'
THUMBNAIL_MARGIN = 2
THUMBNAIL_BORDER = 1
UNKNOWN_ACCOUNT_TYPE = HC.AccountType( 'unknown account', [], ( None, None ) )
def AddPaddingToDimensions( dimensions, padding ):
( x, y ) = dimensions
@ -353,8 +351,6 @@ def GetThumbnailPath( hash ):
return HC.CLIENT_THUMBNAILS_DIR + os.path.sep + first_two_chars + os.path.sep + hash_encoded
def GetUnknownAccount(): return HC.Account( 0, UNKNOWN_ACCOUNT_TYPE, 0, None, ( 0, 0 ) )
def IterateAllFilePaths():
hex_chars = '0123456789abcdef'
@ -403,7 +399,7 @@ def MergeTags( tags_managers ):
# now let's merge so we have s_i : s_t_t
merged_tags = {}
merged_tags = collections.defaultdict( HC.default_dict_set )
for ( service_identifier, several_statuses_to_tags ) in s_i_s_t_t_dict.items():
@ -413,7 +409,7 @@ def MergeTags( tags_managers ):
# [( status, tags )]
flattened_s_t_t = itertools.chain.from_iterable( s_t_t_tupled )
statuses_to_tags = collections.defaultdict( set )
statuses_to_tags = HC.default_dict_set()
for ( status, tags ) in flattened_s_t_t: statuses_to_tags[ status ].update( tags )
@ -605,7 +601,10 @@ def ParseImportablePaths( raw_paths, include_subdirs = True ):
if len( odd_paths ) > 0:
print( 'Because of mime, the client could not import the following files:' )
for odd_path in odd_paths: print( odd_path )
for odd_path in odd_paths:
try: print( odd_path )
except: pass
wx.MessageBox( 'The ' + str( len( odd_paths ) ) + ' files that were not jpegs, pngs, bmps or gifs will not be added. If you are interested, their paths have been written to the log.' )
@ -856,11 +855,9 @@ class CDPPFileServiceIdentifiers():
def HasLocal( self ): return HC.LOCAL_FILE_SERVICE_IDENTIFIER in self._current
def ProcessContentUpdate( self, content_update ):
def ProcessContentUpdate( self, service_identifier, content_update ):
action = content_update.GetAction()
service_identifier = content_update.GetServiceIdentifier()
( data_type, action, row ) = content_update.ToTuple()
if action == HC.CONTENT_UPDATE_ADD:
@ -914,11 +911,9 @@ class LocalRatings():
def GetServiceIdentifiersToRatings( self ): return self._service_identifiers_to_ratings
def ProcessContentUpdate( self, content_update ):
def ProcessContentUpdate( self, service_identifier, content_update ):
service_identifier = content_update.GetServiceIdentifier()
action = content_update.GetAction()
( data_type, action, row ) = content_update.ToTuple()
if action == HC.CONTENT_UPDATE_RATING:
@ -953,7 +948,7 @@ class ConnectionToService():
error_message = 'Could not connect.'
if self._service_identifier is not None: HC.pubsub.pub( 'service_update_db', HC.ServiceUpdate( HC.SERVICE_UPDATE_ERROR, self._service_identifier, error_message ) )
if self._service_identifier is not None: HC.pubsub.pub( 'service_updates_delayed', { self._service_identifier : [ HC.ServiceUpdate( HC.SERVICE_UPDATE_ERROR, error_message ) ] })
raise Exception( error_message )
@ -1114,13 +1109,7 @@ class ConnectionToService():
account.MakeFresh()
HC.pubsub.pub( 'service_update_db', HC.ServiceUpdate( HC.SERVICE_UPDATE_ACCOUNT, self._service_identifier, account ) )
elif request == 'update':
update = response
HC.pubsub.pub( 'service_update_db', HC.ServiceUpdate( HC.SERVICE_UPDATE_NEXT_BEGIN, self._service_identifier, update.GetNextBegin() ) )
wx.GetApp().Write( 'service_updates', { self._service_identifier : [ HC.ServiceUpdate( HC.SERVICE_UPDATE_ACCOUNT, account ) ] } )
return response
@ -1152,9 +1141,9 @@ class CPRemoteRatingsServiceIdentifiers():
def GetServiceIdentifiersToCP( self ): return self._service_identifiers_to_cp
def ProcessContentUpdate( self, content_update ):
def ProcessContentUpdate( self, service_identifier, content_update ):
service_identifier = content_update.GetServiceIdentifier()
( data_type, action, row ) = content_update.ToTuple()
if service_identifier in self._service_identifiers_to_cp: ( current, pending ) = self._service_identifiers_to_cp[ service_identifier ]
else:
@ -1164,8 +1153,6 @@ class CPRemoteRatingsServiceIdentifiers():
self._service_identifiers_to_cp[ service_identifier ] = ( current, pending )
action = content_update.GetAction()
# this may well need work; need to figure out how to set the pending back to None after an upload. rescind seems ugly
if action == HC.CONTENT_UPDATE_ADD:
@ -1305,7 +1292,7 @@ class FileQueryResult():
self._hashes = set( self._hashes_ordered )
HC.pubsub.sub( self, 'ProcessContentUpdates', 'content_updates_data' )
HC.pubsub.sub( self, 'ProcessServiceUpdate', 'service_update_data' )
HC.pubsub.sub( self, 'ProcessServiceUpdates', 'service_updates_data' )
HC.pubsub.sub( self, 'RecalcCombinedTags', 'new_tag_service_precedence' )
@ -1350,56 +1337,64 @@ class FileQueryResult():
def GetMediaResults( self ): return [ self._hashes_to_media_results[ hash ] for hash in self._hashes_ordered ]
def ProcessContentUpdates( self, content_updates ):
def ProcessContentUpdates( self, service_identifiers_to_content_updates ):
for content_update in content_updates:
for ( service_identifier, content_updates ) in service_identifiers_to_content_updates.items():
action = content_update.GetAction()
service_identifier = content_update.GetServiceIdentifier()
service_type = service_identifier.GetType()
hashes = content_update.GetHashes()
if action == HC.CONTENT_UPDATE_ARCHIVE:
for content_update in content_updates:
if 'system:inbox' in self._predicates: self._Remove( hashes )
hashes = content_update.GetHashes()
elif action == HC.CONTENT_UPDATE_INBOX:
if 'system:archive' in self._predicates: self._Remove( hashes )
elif action == HC.CONTENT_UPDATE_DELETE and service_identifier == self._file_service_identifier: self._Remove( hashes )
for hash in self._hashes.intersection( hashes ):
media_result = self._hashes_to_media_results[ hash ]
media_result.ProcessContentUpdate( content_update )
if len( hashes ) > 0:
( data_type, action, row ) = content_update.ToTuple()
service_type = service_identifier.GetType()
if action == HC.CONTENT_UPDATE_ARCHIVE:
if 'system:inbox' in self._predicates: self._Remove( hashes )
elif action == HC.CONTENT_UPDATE_INBOX:
if 'system:archive' in self._predicates: self._Remove( hashes )
elif action == HC.CONTENT_UPDATE_DELETE and service_identifier == self._file_service_identifier: self._Remove( hashes )
for hash in self._hashes.intersection( hashes ):
media_result = self._hashes_to_media_results[ hash ]
media_result.ProcessContentUpdate( service_identifier, content_update )
def ProcessServiceUpdate( self, update ):
def ProcessServiceUpdates( self, service_identifiers_to_service_updates ):
action = update.GetAction()
service_identifier = update.GetServiceIdentifier()
if action == HC.SERVICE_UPDATE_DELETE_PENDING:
for ( service_identifier, service_updates ) in service_identifiers_to_service_updates.items():
for media_result in self._hashes_to_media_results.values(): media_result.DeletePending( service_identifier )
elif action == HC.SERVICE_UPDATE_RESET:
for media_result in self._hashes_to_media_results.values(): media_result.ResetService( service_identifier )
for service_update in service_updates:
( action, row ) = service_update.ToTuple()
if action == HC.SERVICE_UPDATE_DELETE_PENDING:
for media_result in self._hashes_to_media_results.values(): media_result.DeletePending( service_identifier )
elif action == HC.SERVICE_UPDATE_RESET:
for media_result in self._hashes_to_media_results.values(): media_result.ResetService( service_identifier )
class FileSearchContext():
def __init__( self, file_service_identifier = HC.LOCAL_FILE_SERVICE_IDENTIFIER, tag_service_identifier = HC.COMBINED_TAG_SERVICE_IDENTIFIER, include_current_tags = True, include_pending_tags = True, predicates = [] ):
def __init__( self, file_service_identifier = HC.COMBINED_FILE_SERVICE_IDENTIFIER, tag_service_identifier = HC.COMBINED_TAG_SERVICE_IDENTIFIER, include_current_tags = True, include_pending_tags = True, predicates = [] ):
self._file_service_identifier = file_service_identifier
self._tag_service_identifier = tag_service_identifier
@ -1816,7 +1811,7 @@ class Imageboard( HC.HydrusYAMLBase ):
def IsOkToPost( self, media_result ):
( hash, inbox, size, mime, timestamp, width, height, duration, num_frames, num_words, tags, file_service_identifiers, local_ratings, remote_ratings ) = media_result.GetInfo()
( hash, inbox, size, mime, timestamp, width, height, duration, num_frames, num_words, tags, file_service_identifiers, local_ratings, remote_ratings ) = media_result.ToTuple()
if RESTRICTION_MIN_RESOLUTION in self._restrictions:
@ -2009,23 +2004,21 @@ class MediaResult():
def GetTimestamp( self ): return self._tuple[4]
def GetInfo( self ): return self._tuple
def ProcessContentUpdate( self, content_update ):
def ProcessContentUpdate( self, service_identifier, content_update ):
( data_type, action, row ) = content_update.ToTuple()
( hash, inbox, size, mime, timestamp, width, height, duration, num_frames, num_words, tags_manager, file_service_identifiers_cdpp, local_ratings, remote_ratings ) = self._tuple
service_identifier = content_update.GetServiceIdentifier()
service_type = service_identifier.GetType()
if service_type in ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ): tags_manager.ProcessContentUpdate( content_update )
if service_type in ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ):
try: tags_manager.ProcessContentUpdate( service_identifier, content_update )
except: print( traceback.format_exc() )
elif service_type in ( HC.FILE_REPOSITORY, HC.LOCAL_FILE ):
if service_type == HC.LOCAL_FILE:
action = content_update.GetAction()
if action == HC.CONTENT_UPDATE_ADD and not file_service_identifiers_cdpp.HasLocal(): inbox = True
elif action == HC.CONTENT_UPDATE_ARCHIVE: inbox = False
elif action == HC.CONTENT_UPDATE_INBOX: inbox = True
@ -2034,12 +2027,12 @@ class MediaResult():
self._tuple = ( hash, inbox, size, mime, timestamp, width, height, duration, num_frames, num_words, tags_manager, file_service_identifiers_cdpp, local_ratings, remote_ratings )
file_service_identifiers_cdpp.ProcessContentUpdate( content_update )
file_service_identifiers_cdpp.ProcessContentUpdate( service_identifier, content_update )
elif service_type in HC.RATINGS_SERVICES:
if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): local_ratings.ProcessContentUpdate( content_update )
else: remote_ratings.ProcessContentUpdate( content_update )
if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): local_ratings.ProcessContentUpdate( service_identifier, content_update )
else: remote_ratings.ProcessContentUpdate( service_identifier, content_update )
@ -2053,6 +2046,8 @@ class MediaResult():
elif service_type == HC.FILE_REPOSITORY: file_service_identifiers_cdpp.ResetService( service_identifier )
def ToTuple( self ): return self._tuple
class MenuEventIdToActionCache():
def __init__( self ):
@ -2203,7 +2198,7 @@ class ServiceRemote( Service ):
self._credentials = credentials
self._last_error = last_error
HC.pubsub.sub( self, 'ProcessServiceUpdate', 'service_update_data' )
HC.pubsub.sub( self, 'ProcessServiceUpdates', 'service_updates_data' )
def GetConnection( self ): return ConnectionToService( self._service_identifier, self._credentials )
@ -2216,18 +2211,24 @@ class ServiceRemote( Service ):
def SetCredentials( self, credentials ): self._credentials = credentials
def ProcessServiceUpdate( self, update ):
def ProcessServiceUpdates( self, service_identifiers_to_service_updates ):
if update.GetServiceIdentifier() == self._service_identifier:
for ( service_identifier, service_updates ) in service_identifiers_to_service_updates.items():
action = update.GetAction()
if action == HC.SERVICE_UPDATE_ERROR: self._last_error = int( time.time() )
elif action == HC.SERVICE_UPDATE_RESET:
for service_update in service_updates:
self._service_identifier = update.GetInfo()
self._last_error = 0
if service_identifier == self._service_identifier:
( action, row ) = service_update.ToTuple()
if action == HC.SERVICE_UPDATE_ERROR: self._last_error = int( time.time() )
elif action == HC.SERVICE_UPDATE_RESET:
self._service_identifier = row
self._last_error = 0
@ -2269,26 +2270,32 @@ class ServiceRemoteRestricted( ServiceRemote ):
else: return True
def ProcessServiceUpdate( self, update ):
def ProcessServiceUpdates( self, service_identifiers_to_service_updates ):
ServiceRemote.ProcessServiceUpdate( self, update )
ServiceRemote.ProcessServiceUpdates( self, service_identifiers_to_service_updates )
if update.GetServiceIdentifier() == self.GetServiceIdentifier():
for ( service_identifier, service_updates ) in service_identifiers_to_service_updates.items():
action = update.GetAction()
if action == HC.SERVICE_UPDATE_ACCOUNT:
for service_update in service_updates:
account = update.GetInfo()
self._account = account
self._last_error = 0
elif action == HC.SERVICE_UPDATE_REQUEST_MADE:
num_bytes = update.GetInfo()
self._account.RequestMade( num_bytes )
if service_identifier == self.GetServiceIdentifier():
( action, row ) = service_update.ToTuple()
if action == HC.SERVICE_UPDATE_ACCOUNT:
account = row
self._account = account
self._last_error = 0
elif action == HC.SERVICE_UPDATE_REQUEST_MADE:
num_bytes = row
self._account.RequestMade( num_bytes )
@ -2337,26 +2344,34 @@ class ServiceRemoteRestrictedRepository( ServiceRemoteRestricted ):
def ProcessServiceUpdate( self, update ):
def ProcessServiceUpdates( self, service_identifiers_to_service_updates ):
ServiceRemoteRestricted.ProcessServiceUpdate( self, update )
ServiceRemoteRestricted.ProcessServiceUpdates( self, service_identifiers_to_service_updates )
if update.GetServiceIdentifier() == self.GetServiceIdentifier():
for ( service_identifier, service_updates ) in service_identifiers_to_service_updates.items():
action = update.GetAction()
if action == HC.SERVICE_UPDATE_NEXT_BEGIN:
for service_update in service_updates:
next_begin = update.GetInfo()
self.SetNextBegin( next_begin )
elif action == HC.SERVICE_UPDATE_RESET:
self._service_identifier = update.GetInfo()
self._first_begin = 0
self._next_begin = 0
if service_identifier == self.GetServiceIdentifier():
( action, row ) = service_update.ToTuple()
if action == HC.SERVICE_UPDATE_NEXT_BEGIN:
( begin, end ) = row
next_begin = end + 1
self.SetNextBegin( next_begin )
elif action == HC.SERVICE_UPDATE_RESET:
self._service_identifier = row
self._first_begin = 0
self._next_begin = 0
@ -2423,28 +2438,32 @@ class ServiceRemoteRestrictedDepot( ServiceRemoteRestricted ):
def HasCheckDue( self ): return self._last_check + self._check_period + 5 < int( time.time() )
def ProcessServiceUpdate( self, update ):
def ProcessServiceUpdates( self, service_identifiers_to_service_updates ):
ServiceRemoteRestricted.ProcessServiceUpdate( self, update )
ServiceRemoteRestricted.ProcessServiceUpdates( self, update )
if update.GetServiceIdentifier() == self.GetServiceIdentifier():
for ( service_identifier, service_updates ) in service_identifiers_to_service_updates.items():
action = update.GetAction()
if action == HC.SERVICE_UPDATE_LAST_CHECK:
for service_update in service_updates:
last_check = update.GetInfo()
if service_identifier == self.GetServiceIdentifier():
( action, row ) = service_update.ToTuple()
if action == HC.SERVICE_UPDATE_LAST_CHECK:
last_check = row
self._last_check = last_check
elif action == HC.SERVICE_UPDATE_RESET:
self._service_identifier = row
self._last_check = 0
self._last_check = last_check
elif action == HC.SERVICE_UPDATE_RESET:
self._service_identifier = update.GetInfo()
self._last_check = 0
class ServiceRemoteRestrictedDepotMessage( ServiceRemoteRestrictedDepot ):
@ -2491,17 +2510,14 @@ class TagsManager():
for service_identifier in t_s_p:
if service_identifier in self._service_identifiers_to_statuses_to_tags:
statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ service_identifier ]
combined_current.update( statuses_to_tags[ HC.CURRENT ] )
combined_current.difference_update( statuses_to_tags[ HC.DELETED ] )
combined_current.difference_update( statuses_to_tags[ HC.DELETED_PENDING ] )
combined_pending.update( statuses_to_tags[ HC.DELETED_PENDING ] )
combined_pending.update( statuses_to_tags[ HC.PENDING ] )
statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ service_identifier ]
combined_current.update( statuses_to_tags[ HC.CURRENT ] )
combined_current.difference_update( statuses_to_tags[ HC.DELETED ] )
combined_current.difference_update( statuses_to_tags[ HC.DELETED_PENDING ] )
combined_pending.update( statuses_to_tags[ HC.DELETED_PENDING ] )
combined_pending.update( statuses_to_tags[ HC.PENDING ] )
combined_statuses_to_tags = collections.defaultdict( set )
@ -2523,31 +2539,28 @@ class TagsManager():
self._chapters = set()
self._pages = set()
if HC.COMBINED_TAG_SERVICE_IDENTIFIER in self._service_identifiers_to_statuses_to_tags:
combined_statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ HC.COMBINED_TAG_SERVICE_IDENTIFIER ]
combined_current = combined_statuses_to_tags[ HC.CURRENT ]
combined_pending = combined_statuses_to_tags[ HC.PENDING ]
for tag in combined_current.union( combined_pending ):
combined_statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ HC.COMBINED_TAG_SERVICE_IDENTIFIER ]
combined_current = combined_statuses_to_tags[ HC.CURRENT ]
combined_pending = combined_statuses_to_tags[ HC.PENDING ]
for tag in combined_current.union( combined_pending ):
if ':' in tag:
if ':' in tag:
( namespace, tag ) = tag.split( ':', 1 )
if namespace == 'creator': self._creators.add( tag )
elif namespace == 'series': self._series.add( tag )
elif namespace == 'title': self._titles.add( tag )
elif namespace in ( 'volume', 'chapter', 'page' ):
( namespace, tag ) = tag.split( ':', 1 )
try: tag = int( tag )
except: pass
if namespace == 'creator': self._creators.add( tag )
elif namespace == 'series': self._series.add( tag )
elif namespace == 'title': self._titles.add( tag )
elif namespace in ( 'volume', 'chapter', 'page' ):
try: tag = int( tag )
except: pass
if namespace == 'volume': self._volumes.add( tag )
elif namespace == 'chapter': self._chapters.add( tag )
elif namespace == 'page': self._pages.add( tag )
if namespace == 'volume': self._volumes.add( tag )
elif namespace == 'chapter': self._chapters.add( tag )
elif namespace == 'page': self._pages.add( tag )
@ -2564,57 +2577,42 @@ class TagsManager():
def DeletePending( self, service_identifier ):
if service_identifier in self._service_identifiers_to_statuses_to_tags:
statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ service_identifier ]
if len( statuses_to_tags[ HC.PENDING ] ) + len( statuses_to_tags[ HC.DELETED_PENDING ] ) + len( statuses_to_tags[ HC.PETITIONED ] ) > 0:
statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ service_identifier ]
statuses_to_tags[ HC.DELETED ].update( statuses_to_tags[ HC.DELETED_PENDING ] )
if len( statuses_to_tags[ HC.PENDING ] ) + len( statuses_to_tags[ HC.DELETED_PENDING ] ) + len( statuses_to_tags[ HC.PETITIONED ] ) > 0:
statuses_to_tags[ HC.DELETED ].update( statuses_to_tags[ HC.DELETED_PENDING ] )
statuses_to_tags[ HC.PENDING ] = set()
statuses_to_tags[ HC.DELETED_PENDING ] = set()
statuses_to_tags[ HC.PETITIONED ] = set()
self._RecalcCombined()
statuses_to_tags[ HC.PENDING ] = set()
statuses_to_tags[ HC.DELETED_PENDING ] = set()
statuses_to_tags[ HC.PETITIONED ] = set()
self._RecalcCombined()
def GetCurrent( self, service_identifier = HC.COMBINED_TAG_SERVICE_IDENTIFIER ):
if service_identifier in self._service_identifiers_to_statuses_to_tags:
statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ service_identifier ]
return set( statuses_to_tags[ HC.CURRENT ] )
else: return set()
statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ service_identifier ]
return set( statuses_to_tags[ HC.CURRENT ] )
def GetDeleted( self, service_identifier = HC.COMBINED_TAG_SERVICE_IDENTIFIER ):
if service_identifier in self._service_identifiers_to_statuses_to_tags:
statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ service_identifier ]
return statuses_to_tags[ HC.DELETED ].union( statuses_to_tags[ HC.DELETED_PENDING ] )
else: return set()
statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ service_identifier ]
return statuses_to_tags[ HC.DELETED ].union( statuses_to_tags[ HC.DELETED_PENDING ] )
def GetNamespaceSlice( self, namespaces ):
if HC.COMBINED_TAG_SERVICE_IDENTIFIER in self._service_identifiers_to_statuses_to_tags:
combined_statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ HC.COMBINED_TAG_SERVICE_IDENTIFIER ]
combined_current = combined_statuses_to_tags[ HC.CURRENT ]
combined_pending = combined_statuses_to_tags[ HC.PENDING ]
return frozenset( [ tag for tag in list( combined_current ) + list( combined_pending ) if True in ( tag.startswith( namespace + ':' ) for namespace in namespaces ) ] )
else: return frozenset()
combined_statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ HC.COMBINED_TAG_SERVICE_IDENTIFIER ]
combined_current = combined_statuses_to_tags[ HC.CURRENT ]
combined_pending = combined_statuses_to_tags[ HC.PENDING ]
return frozenset( ( tag for tag in list( combined_current ) + list( combined_pending ) if True in ( tag.startswith( namespace + ':' ) for namespace in namespaces ) ) )
def GetNumTags( self, tag_service_identifier, include_current_tags = True, include_pending_tags = False ):
@ -2631,59 +2629,40 @@ class TagsManager():
def GetPending( self, service_identifier = HC.COMBINED_TAG_SERVICE_IDENTIFIER ):
if service_identifier in self._service_identifiers_to_statuses_to_tags:
statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ service_identifier ]
return statuses_to_tags[ HC.DELETED_PENDING ].union( statuses_to_tags[ HC.PENDING ] )
else: return set()
statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ service_identifier ]
return statuses_to_tags[ HC.DELETED_PENDING ].union( statuses_to_tags[ HC.PENDING ] )
def GetPetitioned( self, service_identifier = HC.COMBINED_TAG_SERVICE_IDENTIFIER ):
if service_identifier in self._service_identifiers_to_statuses_to_tags:
statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ service_identifier ]
return set( statuses_to_tags[ HC.PETITIONED ] )
else: return set()
statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ service_identifier ]
return set( statuses_to_tags[ HC.PETITIONED ] )
def GetServiceIdentifiersToStatusesToTags( self ): return self._service_identifiers_to_statuses_to_tags
def GetStatusesToTags( self, service_identifier ):
if service_identifier in self._service_identifiers_to_statuses_to_tags: return self._service_identifiers_to_statuses_to_tags[ service_identifier ]
else: return collections.defaultdict( set )
def GetStatusesToTags( self, service_identifier ): return self._service_identifiers_to_statuses_to_tags[ service_identifier ]
def HasTag( self, tag ):
if HC.COMBINED_TAG_SERVICE_IDENTIFIER in self._service_identifiers_to_statuses_to_tags:
combined_statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ HC.COMBINED_TAG_SERVICE_IDENTIFIER ]
return tag in combined_statuses_to_tags[ HC.CURRENT ] or tag in combined_statuses_to_tags[ HC.PENDING ]
else: return False
combined_statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ HC.COMBINED_TAG_SERVICE_IDENTIFIER ]
return tag in combined_statuses_to_tags[ HC.CURRENT ] or tag in combined_statuses_to_tags[ HC.PENDING ]
def ProcessContentUpdate( self, content_update ):
service_identifier = content_update.GetServiceIdentifier()
if service_identifier not in self._service_identifiers_to_statuses_to_tags: self._service_identifiers_to_statuses_to_tags[ service_identifier ] = collections.defaultdict( set )
def ProcessContentUpdate( self, service_identifier, content_update ):
statuses_to_tags = self._service_identifiers_to_statuses_to_tags[ service_identifier ]
action = content_update.GetAction()
( data_type, action, row ) = content_update.ToTuple()
if action == HC.CONTENT_UPDATE_PETITION: ( tag, hashes, reason ) = row
else: ( tag, hashes ) = row
if action == HC.CONTENT_UPDATE_ADD:
tag = content_update.GetInfo()
statuses_to_tags[ HC.CURRENT ].add( tag )
statuses_to_tags[ HC.DELETED ].discard( tag )
@ -2692,8 +2671,6 @@ class TagsManager():
elif action == HC.CONTENT_UPDATE_DELETE:
tag = content_update.GetInfo()
if tag in statuses_to_tags[ HC.PENDING ]:
statuses_to_tags[ HC.DELETED_PENDING ].add( tag )
@ -2707,84 +2684,38 @@ class TagsManager():
statuses_to_tags[ HC.PETITIONED ].discard( tag )
elif action == HC.CONTENT_UPDATE_EDIT_LOG:
elif action == HC.CONTENT_UPDATE_PENDING:
edit_log = content_update.GetInfo()
for ( action, info ) in edit_log:
if tag in statuses_to_tags[ HC.DELETED ]:
if action == HC.CONTENT_UPDATE_ADD:
tag = info
statuses_to_tags[ HC.CURRENT ].add( tag )
statuses_to_tags[ HC.DELETED ].discard( tag )
statuses_to_tags[ HC.DELETED_PENDING ].discard( tag )
statuses_to_tags[ HC.PENDING ].discard( tag )
elif action == HC.CONTENT_UPDATE_DELETE:
tag = info
if tag in statuses_to_tags[ HC.PENDING ]:
statuses_to_tags[ HC.DELETED_PENDING ].add( tag )
statuses_to_tags[ HC.PENDING ].discard( tag )
else:
statuses_to_tags[ HC.DELETED ].add( tag )
statuses_to_tags[ HC.CURRENT ].discard( tag )
statuses_to_tags[ HC.PETITIONED ].discard( tag )
elif action == HC.CONTENT_UPDATE_PENDING:
tag = info
if tag in statuses_to_tags[ HC.DELETED ]:
statuses_to_tags[ HC.DELETED_PENDING ].add( tag )
statuses_to_tags[ HC.DELETED ].discard( tag )
else: statuses_to_tags[ HC.PENDING ].add( tag )
elif action == HC.CONTENT_UPDATE_RESCIND_PENDING:
tag = info
if tag in statuses_to_tags[ HC.DELETED_PENDING ]:
statuses_to_tags[ HC.DELETED ].add( tag )
statuses_to_tags[ HC.DELETED_PENDING ].discard( tag )
else: statuses_to_tags[ HC.PENDING ].discard( tag )
elif action == HC.CONTENT_UPDATE_PETITION:
( tag, reason ) = info
statuses_to_tags[ HC.PETITIONED ].add( tag )
elif action == HC.CONTENT_UPDATE_RESCIND_PETITION:
tag = info
statuses_to_tags[ HC.PETITIONED ].discard( tag )
statuses_to_tags[ HC.DELETED_PENDING ].add( tag )
statuses_to_tags[ HC.DELETED ].discard( tag )
else: statuses_to_tags[ HC.PENDING ].add( tag )
elif action == HC.CONTENT_UPDATE_RESCIND_PENDING:
if tag in statuses_to_tags[ HC.DELETED_PENDING ]:
statuses_to_tags[ HC.DELETED ].add( tag )
statuses_to_tags[ HC.DELETED_PENDING ].discard( tag )
else: statuses_to_tags[ HC.PENDING ].discard( tag )
elif action == HC.CONTENT_UPDATE_PETITION: statuses_to_tags[ HC.PETITIONED ].add( tag )
elif action == HC.CONTENT_UPDATE_RESCIND_PETITION: statuses_to_tags[ HC.PETITIONED ].discard( tag )
self._RecalcCombined()
def ResetService( self, service_identifier ):
self._service_identifiers_to_statuses_to_tags[ service_identifier ] = collections.defaultdict[ set ]
self._RecalcCombined()
if service_identifier in self._service_identifiers_to_statuses_to_tags:
del self._service_identifiers_to_statuses_to_tags[ service_identifier ]
self._RecalcCombined()
class TagParentsManager():
@ -2831,11 +2762,16 @@ class TagParentsManager():
def _RefreshParents( self ):
raw_parents = wx.GetApp().Read( 'tag_parents' )
service_identifiers_to_statuses_to_pairs = wx.GetApp().Read( 'tag_parents' )
self._parents = collections.defaultdict( dict )
for ( service_identifier, pairs ) in raw_parents.items(): self._parents[ service_identifier ] = HC.BuildKeyToListDict( pairs )
for ( service_identifier, statuses_to_pairs ) in service_identifiers_to_statuses_to_pairs.items():
pairs = statuses_to_pairs[ HC.CURRENT ].union( statuses_to_pairs[ HC.DELETED_PENDING ] ).union( statuses_to_pairs[ HC.PENDING ] )
self._parents[ service_identifier ] = HC.BuildKeyToListDict( pairs )
def ExpandPredicates( self, service_identifier, predicates ):
@ -2886,6 +2822,7 @@ class TagSiblingsManager():
self._tag_service_precedence = wx.GetApp().Read( 'tag_service_precedence' )
# I should offload this to a thread (rather than the gui thread), and have an event to say when it is ready
# gui requests should pause until it is ready, which should kick in during refreshes, too!
self._RefreshSiblings()
@ -2896,7 +2833,7 @@ class TagSiblingsManager():
def _RefreshSiblings( self ):
unprocessed_siblings = wx.GetApp().Read( 'tag_siblings' )
service_identifiers_to_statuses_to_pairs = wx.GetApp().Read( 'tag_siblings' )
t_s_p = list( self._tag_service_precedence )
@ -2909,35 +2846,33 @@ class TagSiblingsManager():
for service_identifier in t_s_p:
if service_identifier in unprocessed_siblings:
statuses_to_pairs = service_identifiers_to_statuses_to_pairs[ service_identifier ]
pairs = statuses_to_pairs[ HC.CURRENT ].union( statuses_to_pairs[ HC.DELETED_PENDING ] ).union( statuses_to_pairs[ HC.PENDING ] )
for ( old, new ) in pairs:
some_siblings = unprocessed_siblings[ service_identifier ]
for ( old, new ) in some_siblings:
if old not in processed_siblings:
if old not in processed_siblings:
next_new = new
we_have_a_loop = False
while next_new in processed_siblings:
next_new = new
next_new = processed_siblings[ next_new ]
we_have_a_loop = False
while next_new in processed_siblings:
if next_new == old:
next_new = processed_siblings[ next_new ]
we_have_a_loop = True
if next_new == old:
we_have_a_loop = True
break
break
if not we_have_a_loop: processed_siblings[ old ] = new
if not we_have_a_loop: processed_siblings[ old ] = new
processed_siblings.update( unprocessed_siblings[ service_identifier ] )
# now to collapse chains

View File

@ -184,7 +184,7 @@ class Controller( wx.App ):
message = 'This instance of the client had a problem connecting to the database, which probably means an old instance is still closing.'
message += os.linesep + os.linesep
message += 'If the old instance does not close for a very long time, you can usually safely force-close it from task manager.'
message += 'If the old instance does not close for a _very_ long time, you can usually safely force-close it from task manager.'
with ClientGUIDialogs.DialogYesNo( None, message, yes_label = 'wait a bit, then try again', no_label = 'quit now' ) as dlg:

File diff suppressed because it is too large Load Diff

View File

@ -105,17 +105,9 @@ class FrameGUI( ClientGUICommon.Frame ):
def _THREADUploadPending( self, service_identifier, job_key, cancel_event ):
# old:
#wx.GetApp().Write( 'upload_pending', service_identifier, job_key, cancel_event )
#return
# new
try:
HC.pubsub.pub( 'progress_update', job_key, 0, 4, u'gathering pending and petitioned' )
HC.pubsub.pub( 'progress_update', job_key, 0, 3, u'gathering pending and petitioned' )
result = wx.GetApp().Read( 'pending', service_identifier )
@ -123,113 +115,106 @@ class FrameGUI( ClientGUICommon.Frame ):
service = wx.GetApp().Read( 'service', service_identifier )
if service_type == HC.TAG_REPOSITORY:
if service_type == HC.FILE_REPOSITORY:
( mappings_object, petitions_object ) = result
( upload_hashes, update ) = result
if len( mappings_object ) > 0 or len( petitions_object ) > 0:
num_uploads = len( upload_hashes )
HC.pubsub.pub( 'progress_update', job_key, 1, num_uploads + 3, u'connecting to repository' )
connection = service.GetConnection()
good_hashes = []
error_messages = set()
for ( index, hash ) in enumerate( upload_hashes ):
HC.pubsub.pub( 'progress_update', job_key, 1, 4, u'connecting to repository' )
HC.pubsub.pub( 'progress_update', job_key, index + 2, num_uploads + 3, u'Uploading file ' + HC.ConvertIntToPrettyString( index + 1 ) + ' of ' + HC.ConvertIntToPrettyString( num_uploads ) )
connection = service.GetConnection()
if cancel_event.isSet(): break
if len( mappings_object ) > 0:
try:
HC.pubsub.pub( 'progress_update', job_key, 2, 4, u'posting new mappings' )
file = wx.GetApp().Read( 'file', hash )
try: connection.Post( 'mappings', mappings = mappings_object )
except Exception as e: raise Exception( 'Encountered an error while uploading public_mappings:' + os.linesep + unicode( e ) )
connection.Post( 'file', file = file )
if len( petitions_object ) > 0:
good_hashes.append( hash )
HC.pubsub.pub( 'progress_update', job_key, 3, 4, u'posting new petitions' )
except Exception as e:
try: connection.Post( 'petitions', petitions = petitions_object )
except Exception as e: raise Exception( 'Encountered an error while uploading petitions:' + os.linesep + unicode( e ) )
message = 'Error: ' + unicode( e )
HC.pubsub.pub( 'progress_update', job_key, num_uploads + 1, num_uploads + 3, message )
print( message )
time.sleep( 1 )
num_mappings = sum( [ len( hashes ) for ( tag, hashes ) in mappings_object ] )
num_deleted_mappings = sum( [ len( hashes ) for ( reason, tag, hashes ) in petitions_object ] )
HC.pubsub.pub( 'log_message', 'upload mappings', 'uploaded ' + HC.ConvertIntToPrettyString( num_mappings ) + ' mappings to and deleted ' + HC.ConvertIntToPrettyString( num_deleted_mappings ) + ' mappings from ' + service_identifier.GetName() )
content_updates = []
content_updates += [ HC.ContentUpdate( HC.CONTENT_UPDATE_ADD, service_identifier, hashes, info = tag ) for ( tag, hashes ) in mappings_object ]
content_updates += [ HC.ContentUpdate( HC.CONTENT_UPDATE_DELETE, service_identifier, hashes, info = tag ) for ( reason, tag, hashes ) in petitions_object ]
wx.GetApp().Write( 'content_updates', content_updates )
elif service_type == HC.FILE_REPOSITORY:
if len( good_hashes ) > 0: HC.pubsub.pub( 'log_message', 'upload files', 'uploaded ' + HC.ConvertIntToPrettyString( len( good_hashes ) ) + ' files to ' + service_identifier.GetName() )
( uploads, petitions_object ) = result
( num_uploads, num_petitions ) = ( len( uploads ), len( petitions_object ) )
if num_uploads > 0 or num_petitions > 0:
if not update.IsEmpty():
HC.pubsub.pub( 'progress_update', job_key, 1, num_uploads + 3, u'connecting to repository' )
connection = service.GetConnection()
good_hashes = []
if num_uploads > 0:
try:
error_messages = set()
HC.pubsub.pub( 'progress_update', job_key, num_uploads + 1, num_uploads + 3, u'uploading petitions' )
for ( index, hash ) in enumerate( uploads ):
HC.pubsub.pub( 'progress_update', job_key, index + 2, num_uploads + 3, u'Uploading file ' + HC.ConvertIntToPrettyString( index + 1 ) + ' of ' + HC.ConvertIntToPrettyString( num_uploads ) )
if cancel_event.isSet(): break
try:
file = wx.GetApp().Read( 'file', hash )
connection.Post( 'file', file = file )
good_hashes.append( hash )
except Exception as e:
message = 'Error: ' + unicode( e )
HC.pubsub.pub( 'progress_update', job_key, num_uploads + 1, num_uploads + 3, message )
print( message )
time.sleep( 1 )
connection.Post( 'update', update = update )
HC.pubsub.pub( 'progress_update', job_key, num_uploads + 1, num_uploads + 3, u'saving changes to local database' )
HC.pubsub.pub( 'log_message', 'upload files', 'uploaded a file update to ' + service_identifier.GetName() )
if num_petitions > 0:
except Exception as e:
try:
HC.pubsub.pub( 'progress_update', job_key, num_uploads + 2, num_uploads + 3, u'uploading petitions' )
connection.Post( 'petitions', petitions = petitions_object )
except Exception as e: raise Exception( 'Encountered an error while trying to uploads petitions to '+ service_name + ':' + os.linesep + unicode( e ) )
print( traceback.format_exc() )
raise Exception( 'Encountered an error while trying to uploads petitions to '+ service_identifier.GetName() + ':' + os.linesep + unicode( e ) )
HC.pubsub.pub( 'log_message', 'upload files', 'uploaded ' + HC.ConvertIntToPrettyString( num_uploads ) + ' files to and deleted ' + HC.ConvertIntToPrettyString( num_petitions ) + ' files from ' + service_identifier.GetName() )
content_updates = []
content_updates.append( HC.ContentUpdate( HC.CONTENT_UPDATE_ADD, service_identifier, good_hashes ) )
content_updates.append( HC.ContentUpdate( HC.CONTENT_UPDATE_DELETE, service_identifier, petitions_object.GetHashes() ) )
wx.GetApp().Write( 'content_updates', content_updates )
HC.pubsub.pub( 'progress_update', job_key, num_uploads + 2, num_uploads + 3, u'saving changes to local database' )
content_updates = []
media_results = wx.GetApp().Read( 'media_results', CC.FileSearchContext(), good_hashes )
for media_result in media_results:
( hash, inbox, size, mime, timestamp, width, height, duration, num_frames, num_words, tags_manager, file_service_identifiers_cdpp, local_ratings, remote_ratings ) = media_result.ToTuple()
timestamp = int( time.time() )
content_update_row = ( hash, size, mime, timestamp, width, height, duration, num_frames, num_words )
content_updates.append( HC.ContentUpdate( HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_UPDATE_ADD, content_update_row ) )
content_updates.extend( update.GetContentUpdates( for_client = True ) )
service_identfiers_to_content_updates = { service_identifier : content_updates }
elif service_type == HC.TAG_REPOSITORY:
update = result
HC.pubsub.pub( 'progress_update', job_key, 1, 3, u'connecting to repository' )
connection = service.GetConnection()
HC.pubsub.pub( 'progress_update', job_key, 2, 3, u'posting update' )
try: connection.Post( 'update', update = update )
except Exception as e: raise Exception( 'Encountered an error while uploading tags:' + os.linesep + unicode( e ) )
HC.pubsub.pub( 'log_message', 'upload mappings', 'uploaded a tag update to ' + service_identifier.GetName() )
service_identfiers_to_content_updates = { service_identifier : update.GetContentUpdates( for_client = True ) }
wx.GetApp().Write( 'content_updates', service_identfiers_to_content_updates )
except Exception as e:
@ -1317,8 +1302,8 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
if service_type == HC.TAG_REPOSITORY:
num_pending = info[ HC.SERVICE_INFO_NUM_PENDING_MAPPINGS ]
num_petitioned = info[ HC.SERVICE_INFO_NUM_PETITIONED_MAPPINGS ]
num_pending = info[ HC.SERVICE_INFO_NUM_PENDING_MAPPINGS ] + info[ HC.SERVICE_INFO_NUM_PENDING_TAG_SIBLINGS ] + info[ HC.SERVICE_INFO_NUM_PENDING_TAG_PARENTS ]
num_petitioned = info[ HC.SERVICE_INFO_NUM_PETITIONED_MAPPINGS ] + info[ HC.SERVICE_INFO_NUM_PETITIONED_TAG_SIBLINGS ] + info[ HC.SERVICE_INFO_NUM_PETITIONED_TAG_PARENTS ]
elif service_type == HC.FILE_REPOSITORY:
@ -2081,7 +2066,7 @@ class FrameReviewServicesServicePanel( wx.ScrolledWindow ):
self._timer_updates.Start( 1000, wx.TIMER_CONTINUOUS )
HC.pubsub.sub( self, 'ProcessServiceUpdate', 'service_update_gui' )
HC.pubsub.sub( self, 'ProcessServiceUpdates', 'service_updates_gui' )
HC.pubsub.sub( self, 'AddThumbnailCount', 'add_thumbnail_count' )
@ -2317,20 +2302,24 @@ class FrameReviewServicesServicePanel( wx.ScrolledWindow ):
self._updates_text.SetLabel( HC.ConvertIntToPrettyString( num_updates_downloaded ) + '/' + HC.ConvertIntToPrettyString( num_updates ) + ' - ' + self._service.GetUpdateStatus() )
def ProcessServiceUpdate( self, update ):
def ProcessServiceUpdates( self, service_identifiers_to_service_updates ):
service_identifier = update.GetServiceIdentifier()
if service_identifier == self._service_identifier:
for ( service_identifier, service_updates ) in service_identifiers_to_service_updates.items():
action = update.GetAction()
if action == HC.SERVICE_UPDATE_RESET: self._service_identifier = update.GetInfo()
if action in ( HC.SERVICE_UPDATE_ACCOUNT, HC.SERVICE_UPDATE_REQUEST_MADE ): wx.CallLater( 200, self._DisplayAccountInfo )
else:
wx.CallLater( 200, self._DisplayService )
wx.CallLater( 400, self.Layout ) # ugly hack, but it works for now
for service_update in service_updates:
if service_identifier == self._service_identifier:
( action, row ) = service_update.ToTuple()
if action == HC.SERVICE_UPDATE_RESET: self._service_identifier = row
if action in ( HC.SERVICE_UPDATE_ACCOUNT, HC.SERVICE_UPDATE_REQUEST_MADE ): wx.CallLater( 600, self._DisplayAccountInfo )
else:
wx.CallLater( 200, self._DisplayService )
wx.CallLater( 400, self.Layout ) # ugly hack, but it works for now

View File

@ -482,13 +482,25 @@ class CanvasPanel( Canvas, wx.Window ):
if page_key == self._page_key: self.SetMedia( media )
def ProcessContentUpdates( self, updates ):
def ProcessContentUpdates( self, service_identifiers_to_content_updates ):
if self._current_display_media is not None:
my_hash = self._current_display_media.GetHash()
if True in ( my_hash in update.GetHashes() for update in updates ):
do_redraw = False
for ( service_identifier, content_updates ) in service_identifiers_to_content_updates.items():
if True in ( my_hash in content_update.GetHashes() for content_update in content_updates ):
do_redraw = True
break
if do_redraw:
self._DrawBackgroundBitmap()
@ -937,13 +949,13 @@ class CanvasFullscreenMediaList( ClientGUIMixins.ListeningMediaList, Canvas, Cli
def KeepCursorAlive( self ): self._timer_cursor_hide.Start( 800, wx.TIMER_ONE_SHOT )
def ProcessContentUpdates( self, updates ):
def ProcessContentUpdates( self, service_identifiers_to_content_updates ):
next_media = self._GetNext( self._current_media )
if next_media == self._current_media: next_media = None
ClientGUIMixins.ListeningMediaList.ProcessContentUpdates( self, updates )
ClientGUIMixins.ListeningMediaList.ProcessContentUpdates( self, service_identifiers_to_content_updates )
if self.HasNoMedia(): self.EventClose( None )
elif self.HasMedia( self._current_media ):
@ -980,7 +992,7 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ):
HC.pubsub.sub( self, 'AddMediaResult', 'add_media_result' )
def _Archive( self ): wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( HC.CONTENT_UPDATE_ARCHIVE, HC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] )
def _Archive( self ): wx.GetApp().Write( 'content_updates', { HC.LOCAL_FILE_SERVICE_IDENTIFIER : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPES_FILES, HC.CONTENT_UPDATE_ARCHIVE, ( self._current_media.GetHash(), ) ) ] } )
def _CopyLocalUrlToClipboard( self ):
@ -1012,13 +1024,13 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ):
with ClientGUIDialogs.DialogYesNo( self, 'Delete this file from the database?' ) as dlg:
if dlg.ShowModal() == wx.ID_YES: wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( HC.CONTENT_UPDATE_DELETE, HC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] )
if dlg.ShowModal() == wx.ID_YES: wx.GetApp().Write( 'content_updates', { HC.LOCAL_FILE_SERVICE_IDENTIFIER : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPES_FILES, HC.CONTENT_UPDATE_DELETE, ( self._current_media.GetHash(), ) ) ] } )
self.SetFocus() # annoying bug because of the modal dialog
def _Inbox( self ): wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( HC.CONTENT_UPDATE_INBOX, HC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] )
def _Inbox( self ): wx.GetApp().Write( 'content_updates', { HC.LOCAL_FILE_SERVICE_IDENTIFIER : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPES_FILES, HC.CONTENT_UPDATE_INBOX, ( self._current_media.GetHash(), ) ) ] } )
def _PausePlaySlideshow( self ):
@ -1258,7 +1270,7 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
HC.pubsub.sub( self, 'AddMediaResult', 'add_media_result' )
def _Archive( self ): wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( HC.CONTENT_UPDATE_ARCHIVE, HC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] )
def _Archive( self ): wx.GetApp().Write( 'content_updates', { HC.LOCAL_FILE_SERVICE_IDENTIFIER : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPES_FILES, HC.CONTENT_UPDATE_ARCHIVE, ( self._current_media.GetHash(), ) ) ] } )
def _CopyLocalUrlToClipboard( self ):
@ -1290,13 +1302,13 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
with ClientGUIDialogs.DialogYesNo( self, 'Delete this file from the database?' ) as dlg:
if dlg.ShowModal() == wx.ID_YES: wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( HC.CONTENT_UPDATE_DELETE, HC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] )
if dlg.ShowModal() == wx.ID_YES: wx.GetApp().Write( 'content_updates', { HC.LOCAL_FILE_SERVICE_IDENTIFIER : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPES_FILES, HC.CONTENT_UPDATE_DELETE, ( self._current_media.GetHash(), ) ) ] } )
self.SetFocus() # annoying bug because of the modal dialog
def _Inbox( self ): wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( HC.CONTENT_UPDATE_INBOX, HC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] )
def _Inbox( self ): wx.GetApp().Write( 'content_updates', { HC.LOCAL_FILE_SERVICE_IDENTIFIER : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPES_FILES, HC.CONTENT_UPDATE_INBOX, ( self._current_media.GetHash(), ) ) ] } )
def EventKeyDown( self, event ):
@ -1307,6 +1319,8 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
key_dict = self._actions[ modifier ]
hashes = set( ( self._current_media.GetHash(), ) )
if key in key_dict:
( service_identifier, action ) = key_dict[ key ]
@ -1348,8 +1362,10 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
if service_type == HC.LOCAL_TAG:
if action in current: edit_log = [ ( HC.CONTENT_UPDATE_DELETE, action ) ]
else: edit_log = [ ( HC.CONTENT_UPDATE_ADD, action ) ]
if action in current: content_update_action = HC.CONTENT_UPDATE_DELETE
else: content_update_action = HC.CONTENT_UPDATE_ADD
row = ( action, hashes )
else:
@ -1362,26 +1378,38 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
with wx.TextEntryDialog( self, message ) as dlg:
if dlg.ShowModal() == wx.ID_OK: edit_log = [ ( HC.CONTENT_UPDATE_PETITION, ( action, dlg.GetValue() ) ) ]
if dlg.ShowModal() == wx.ID_OK:
content_update_action = HC.CONTENT_UPDATE_PETITION
row = ( dlg.GetValue(), action, hashes )
else: return
else:
if action in pending: edit_log = [ ( HC.CONTENT_UPDATE_RESCIND_PENDING, action ) ]
else: edit_log = [ ( HC.CONTENT_UPDATE_PENDING, action ) ]
if action in pending: content_update_action = HC.CONTENT_UPDATE_RESCIND_PENDING
else: content_update_action = HC.CONTENT_UPDATE_PENDING
row = ( action, hashes )
content_update = HC.ContentUpdate( HC.CONTENT_UPDATE_EDIT_LOG, service_identifier, ( self._current_media.GetHash(), ), info = edit_log )
content_update = HC.ContentUpdate( HC.CONTENT_DATA_TYPES_MAPPINGS, content_update_action, row )
elif service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ):
content_update = HC.ContentUpdate( HC.CONTENT_UPDATE_RATING, service_identifier, ( self._current_media.GetHash(), ), info = action )
# maybe this needs to be more complicated, if action is, say, remove the rating?
# ratings needs a good look at anyway
row = ( action, hashes )
content_update = HC.ContentUpdate( HC.CONTENT_DATA_TYPES_RATINGS, HC.CONTENT_UPDATE_ADD, row )
wx.GetApp().Write( 'content_updates', ( content_update, ) )
wx.GetApp().Write( 'content_updates', { service_identifier : [ content_update ] } )
else:
@ -1597,10 +1625,10 @@ class CanvasFullscreenMediaListFilter( CanvasFullscreenMediaList ):
content_updates = []
content_updates.append( HC.ContentUpdate( HC.CONTENT_UPDATE_DELETE, HC.LOCAL_FILE_SERVICE_IDENTIFIER, self._deleted_hashes ) )
content_updates.append( HC.ContentUpdate( HC.CONTENT_UPDATE_ARCHIVE, HC.LOCAL_FILE_SERVICE_IDENTIFIER, self._kept_hashes ) )
content_updates.append( HC.ContentUpdate( HC.CONTENT_DATA_TYPES_FILES, HC.CONTENT_UPDATE_DELETE, self._deleted_hashes ) )
content_updates.append( HC.ContentUpdate( HC.CONTENT_DATA_TYPES_FILES, HC.CONTENT_UPDATE_ARCHIVE, self._kept_hashes ) )
wx.GetApp().Write( 'content_updates', content_updates )
wx.GetApp().Write( 'content_updates', { HC.LOCAL_FILE_SERVICE_IDENTIFIER : content_updates } )
self._kept = set()
self._deleted = set()
@ -1778,10 +1806,10 @@ class RatingsFilterFrameLike( CanvasFullscreenMediaListFilter ):
content_updates = []
content_updates.extend( [ HC.ContentUpdate( HC.CONTENT_UPDATE_RATING, self._rating_service_identifier, ( hash, ), info = 0.0 ) for hash in self._deleted_hashes ] )
content_updates.extend( [ HC.ContentUpdate( HC.CONTENT_UPDATE_RATING, self._rating_service_identifier, ( hash, ), info = 1.0 ) for hash in self._kept_hashes ] )
content_updates.extend( [ HC.ContentUpdate( HC.CONTENT_DATA_TYPES_RATINGS, HC.CONTENT_UPDATE_ADD, ( 0.0, set( ( hash, ) ) ) ) for hash in self._deleted_hashes ] )
content_updates.extend( [ HC.ContentUpdate( HC.CONTENT_DATA_TYPES_RATINGS, HC.CONTENT_UPDATE_ADD, ( 1.0, set( ( hash, ) ) ) ) for hash in self._kept_hashes ] )
wx.GetApp().Write( 'content_updates', content_updates )
wx.GetApp().Write( 'content_updates', { self._rating_service_identifier : content_updates } )
self._kept = set()
self._deleted = set()
@ -1917,7 +1945,7 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
self._ShowNewMedia()
HC.pubsub.sub( self, 'ProcessContentUpdates', 'content_updates_gui' )
HC.pubsub.sub( self, 'ProcessServiceUpdate', 'service_update_gui' )
HC.pubsub.sub( self, 'ProcessServiceUpdates', 'service_updates_gui' )
HC.pubsub.pub( 'set_focus', self._page_key, None )
@ -2357,8 +2385,8 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
def normalise_rating( rating ): return round( rating / self._score_gap ) * self._score_gap
certain_ratings = [ ( media.GetHash(), normalise_rating( ( min + max ) / 2 ) ) for ( media, ( min, max ) ) in self._media_to_current_scores_dict.items() if max - min < self._score_gap ]
uncertain_ratings = [ ( media.GetHash(), min, max ) for ( media, ( min, max ) ) in self._media_to_current_scores_dict.items() if max - min >= self._score_gap and self._media_to_current_scores_dict[ media ] != self._media_to_initial_scores_dict[ media ] ]
certain_ratings = [ ( normalise_rating( ( min + max ) / 2 ), media.GetHash() ) for ( media, ( min, max ) ) in self._media_to_current_scores_dict.items() if max - min < self._score_gap ]
uncertain_ratings = [ ( min, max, media.GetHash() ) for ( media, ( min, max ) ) in self._media_to_current_scores_dict.items() if max - min >= self._score_gap and self._media_to_current_scores_dict[ media ] != self._media_to_initial_scores_dict[ media ] ]
with ClientGUIDialogs.DialogFinishRatingFiltering( self, len( certain_ratings ), len( uncertain_ratings ) ) as dlg:
@ -2376,10 +2404,10 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
content_updates = []
content_updates.extend( [ HC.ContentUpdate( HC.CONTENT_UPDATE_RATING, self._service_identifier, ( hash, ), info = rating ) for ( hash, rating ) in certain_ratings ] )
content_updates.extend( [ HC.ContentUpdate( HC.CONTENT_UPDATE_RATINGS_FILTER, self._service_identifier, ( hash, ), info = ( min, max ) ) for ( hash, min, max ) in uncertain_ratings ] )
content_updates.extend( [ HC.ContentUpdate( HC.CONTENT_DATA_TYPE_RATINGS, HC.CONTENT_UPDATE_ADD, ( rating, set( ( hash, ) ) ) ) for ( rating, hash ) in certain_ratings ] )
content_updates.extend( [ HC.ContentUpdate( HC.CONTENT_DATA_TYPE_RATINGS, HC.CONTENT_UPDATE_RATINGS_FILTER, ( min, max, set( ( hash, ) ) ) ) for ( min, max, hash ) in uncertain_ratings ] )
wx.GetApp().Write( 'content_updates', content_updates )
wx.GetApp().Write( 'content_updates', { self._service_identifier : content_updates } )
except: wx.MessageBox( traceback.format_exc() )
@ -2448,21 +2476,24 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
wx.GetApp().Write( 'save_options' )
def ProcessContentUpdates( self, content_updates ):
def ProcessContentUpdates( self, service_identifiers_to_content_updates ):
redraw = False
my_hashes = self._file_query_result.GetHashes()
for content_update in content_updates:
for ( service_identifier, content_updates ) in service_identifiers_to_content_updates.items():
content_update_hashes = content_update.GetHashes()
if len( my_hashes.intersection( content_update_hashes ) ) > 0:
for content_update in content_updates:
redraw = True
content_update_hashes = content_update.GetHashes()
break
if len( my_hashes.intersection( content_update_hashes ) ) > 0:
redraw = True
break
@ -2473,7 +2504,7 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
def ProcessServiceUpdate( self, update ):
def ProcessServiceUpdates( self, service_identifiers_to_service_updates ):
self._left_window.RefreshBackground()
self._right_window.RefreshBackground()

View File

@ -2212,6 +2212,16 @@ class SaneListCtrl( wx.ListCtrl, ListCtrlAutoWidthMixin, ColumnSorterMixin ):
def GetIndexFromClientData( self, data ):
for index in range( self.GetItemCount() ):
if self.GetClientData( index ) == data: return index
raise Exception( 'Data not found!' )
def GetListCtrl( self ): return self
def RemoveAllSelected( self ):
@ -3182,10 +3192,16 @@ class TagsBoxManage( TagsBox ):
for tag in all_tags:
if tag in self._petitioned_tags: tag_string = '(-) ' + tag
elif tag in self._current_tags: tag_string = tag
elif tag in self._pending_tags: tag_string = '(+) ' + tag
else: tag_string = '(X) ' + tag
if tag in self._petitioned_tags: prefix = HC.ConvertStatusToPrefix( HC.PETITIONED )
elif tag in self._current_tags: prefix = HC.ConvertStatusToPrefix( HC.CURRENT )
elif tag in self._pending_tags:
if tag in self._deleted_tags: prefix = HC.ConvertStatusToPrefix( HC.DELETED_PENDING )
else: prefix = HC.ConvertStatusToPrefix( HC.PENDING )
else: prefix = HC.ConvertStatusToPrefix( HC.DELETED )
tag_string = prefix + ' ' + tag
sibling = siblings_manager.GetSibling( tag )

File diff suppressed because it is too large Load Diff

View File

@ -631,7 +631,7 @@ class ManagementPanelDumper( ManagementPanel ):
for ( service_identifier, namespaces ) in advanced_tag_options.items():
tags = media.GetTagsManager()
tags_manager = media.GetTagsManager()
current = tags_manager.GetCurrent( service_identifier )
pending = tags_manager.GetPending( service_identifier )
@ -1697,9 +1697,9 @@ class ManagementPanelImportWithQueueAdvanced( ManagementPanelImportWithQueue ):
service_identifiers_to_tags = HydrusDownloading.ConvertTagsToServiceIdentifiersToTags( tags, advanced_tag_options )
content_updates = HydrusDownloading.ConvertServiceIdentifiersToTagsToContentUpdates( hash, service_identifiers_to_tags )
content_updates = HydrusDownloading.ConvertServiceIdentifiersToTagsToServiceIdentifiersToContentUpdates( hash, service_identifiers_to_tags )
wx.GetApp().WriteDaemon( 'content_updates', content_updates )
wx.GetApp().WriteDaemon( 'content_updates', service_identifiers_to_content_updates )
HC.pubsub.pub( 'import_done', self._page_key, 'redundant' )
@ -2380,11 +2380,13 @@ class ManagementPanelImportThreadWatcher( ManagementPanelImport ):
class ManagementPanelPetitions( ManagementPanel ):
def __init__( self, parent, page, page_key, file_service_identifier ):
def __init__( self, parent, page, page_key, file_service_identifier, petition_service_identifier ):
self._petition_service_identifier = petition_service_identifier
ManagementPanel.__init__( self, parent, page, page_key, file_service_identifier )
self._service = wx.GetApp().Read( 'service', file_service_identifier )
self._service = wx.GetApp().Read( 'service', self._petition_service_identifier )
self._can_ban = self._service.GetAccount().HasPermission( HC.MANAGE_USERS )
self._num_petitions = None
@ -2476,7 +2478,7 @@ class ManagementPanelPetitions( ManagementPanel ):
search_context = CC.FileSearchContext( self._file_service_identifier )
with wx.BusyCursor(): file_query_result = wx.GetApp().Read( 'media_results', search_context, self._current_petition.GetPetitionHashes() )
with wx.BusyCursor(): file_query_result = wx.GetApp().Read( 'media_results', search_context, self._current_petition.GetHashes() )
panel = ClientGUIMedia.MediaPanelThumbnails( self._page, self._page_key, self._file_service_identifier, [], file_query_result )
@ -2498,26 +2500,13 @@ class ManagementPanelPetitions( ManagementPanel ):
def EventApprove( self, event ):
update = self._current_petition.GetApproval()
connection = self._service.GetConnection()
petition_object = self._current_petition.GetClientPetition()
connection.Post( 'update', update = update )
connection.Post( 'petitions', petitions = petition_object )
if isinstance( self._current_petition, HC.ServerFilePetition ):
hashes = self._current_petition.GetPetitionHashes()
content_updates = [ HC.ContentUpdate( HC.CONTENT_UPDATE_DELETE, self._file_service_identifier, hashes ) ]
elif isinstance( self._current_petition, HC.ServerMappingPetition ):
( reason, tag, hashes ) = self._current_petition.GetPetitionInfo()
content_updates = [ HC.ContentUpdate( HC.CONTENT_UPDATE_DELETE, self._file_service_identifier, hashes, tag ) ]
wx.GetApp().WriteDaemon( 'content_updates', content_updates )
wx.GetApp().WriteDaemon( 'content_updates', { self._petition_service_identifier : update.GetContentUpdates( for_client = True ) } )
self._current_petition = None
@ -2528,12 +2517,11 @@ class ManagementPanelPetitions( ManagementPanel ):
def EventDeny( self, event ):
update = self._current_petition.GetDenial()
connection = self._service.GetConnection()
petition_object = self._current_petition.GetClientPetitionDenial()
# needs work
connection.Post( 'petition_denial', petition_denial = petition_object )
connection.Post( 'update', update = update )
self._current_petition = None
@ -2564,7 +2552,7 @@ class ManagementPanelPetitions( ManagementPanel ):
def EventModifyPetitioner( self, event ):
with ClientGUIDialogs.DialogModifyAccounts( self, self._file_service_identifier, ( self._current_petition.GetPetitionerIdentifier(), ) ) as dlg: dlg.ShowModal()
with ClientGUIDialogs.DialogModifyAccounts( self, self._petition_service_identifier, ( self._current_petition.GetPetitionerIdentifier(), ) ) as dlg: dlg.ShowModal()
def EventRefreshNumPetitions( self, event ):

View File

@ -96,7 +96,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
hashes = self._GetSelectedHashes( CC.DISCRIMINANT_INBOX )
if len( hashes ) > 0: wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( HC.CONTENT_UPDATE_ARCHIVE, HC.LOCAL_FILE_SERVICE_IDENTIFIER, hashes ) ] )
if len( hashes ) > 0: wx.GetApp().Write( 'content_updates', { HC.LOCAL_FILE_SERVICE_IDENTIFIER : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_UPDATE_ARCHIVE, hashes ) ] } )
def _CopyHashToClipboard( self ):
@ -189,7 +189,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
if dlg.ShowModal() == wx.ID_YES:
try: wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( HC.CONTENT_UPDATE_DELETE, file_service_identifier, hashes ) ] )
try: wx.GetApp().Write( 'content_updates', { file_service_identifier : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_UPDATE_DELETE, hashes ) ] } )
except: wx.MessageBox( traceback.format_exc() )
@ -199,7 +199,11 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
hashes = self._GetSelectedHashes()
wx.GetApp().Write( 'petition_files', file_service_identifier, hashes, 'admin' )
content_update = HC.ContentUpdate( HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_UPDATE_PETITION, ( hashes, 'admin' ) )
service_identifiers_to_content_updates = { file_service_identifier : ( content_update, ) }
wx.GetApp().Write( 'content_updates', service_identifiers_to_content_updates )
@ -299,7 +303,14 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
def _GetSelectedHashes( self, discriminant = None, not_uploaded_to = None ): return HC.IntelligentMassUnion( ( media.GetHashes( discriminant, not_uploaded_to ) for media in self._selected_media ) )
def _GetSelectedHashes( self, discriminant = None, not_uploaded_to = None ):
result = set()
for media in self._selected_media: result.update( media.GetHashes( discriminant, not_uploaded_to ) )
return result
def _GetSimilarTo( self ):
@ -366,7 +377,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
hashes = self._GetSelectedHashes( CC.DISCRIMINANT_ARCHIVE )
if len( hashes ) > 0: wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( HC.CONTENT_UPDATE_INBOX, HC.LOCAL_FILE_SERVICE_IDENTIFIER, hashes ) ] )
if len( hashes ) > 0: wx.GetApp().Write( 'content_updates', { HC.LOCAL_FILE_SERVICE_IDENTIFIER : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_UPDATE_INBOX, hashes ) ] } )
def _ManageRatings( self ):
@ -444,7 +455,14 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
with wx.TextEntryDialog( self, message ) as dlg:
if dlg.ShowModal() == wx.ID_OK: wx.GetApp().Write( 'petition_files', file_service_identifier, hashes, dlg.GetValue() )
if dlg.ShowModal() == wx.ID_OK:
content_update = HC.ContentUpdate( HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_UPDATE_PETITION, ( hashes, dlg.GetValue() ) )
service_identifiers_to_content_updates = { file_service_identifier : ( content_update, ) }
wx.GetApp().Write( 'content_updates', service_identifiers_to_content_updates )
self.SetFocus()
@ -574,7 +592,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
if hashes is not None and len( hashes ) > 0:
try: wx.GetApp().Write( 'add_uploads', file_service_identifier, hashes )
try: wx.GetApp().Write( 'content_updates', { file_service_identifier : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_UPDATE_PENDING, hashes ) ] } )
except Exception as e: wx.MessageBox( unicode( e ) )
@ -638,25 +656,26 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
def ProcessContentUpdates( self, content_updates ):
def ProcessContentUpdates( self, service_identifiers_to_content_updates ):
ClientGUIMixins.ListeningMediaList.ProcessContentUpdates( self, content_updates )
ClientGUIMixins.ListeningMediaList.ProcessContentUpdates( self, service_identifiers_to_content_updates )
for content_update in content_updates:
service_identifier = content_update.GetServiceIdentifier()
for ( service_identifier, content_updates ) in service_identifiers_to_content_updates.items():
service_type = service_identifier.GetType()
hashes = content_update.GetHashes()
affected_media = self._GetMedia( hashes )
action = content_update.GetAction()
if action == HC.CONTENT_UPDATE_DELETE and service_type in ( HC.FILE_REPOSITORY, HC.LOCAL_FILE ) and self._focussed_media in affected_media: self._SetFocussedMedia( None )
if len( affected_media ) > 0: self._ReblitMedia( affected_media )
for content_update in content_updates:
( data_type, action, row ) = content_update.ToTuple()
hashes = content_update.GetHashes()
affected_media = self._GetMedia( hashes )
if action == HC.CONTENT_UPDATE_DELETE and service_type in ( HC.FILE_REPOSITORY, HC.LOCAL_FILE ) and self._focussed_media in affected_media: self._SetFocussedMedia( None )
if len( affected_media ) > 0: self._ReblitMedia( affected_media )
self._PublishSelectionChange()
@ -664,22 +683,26 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
if self._focussed_media is not None: self._HitMedia( self._focussed_media, False, False )
def ProcessServiceUpdate( self, update ):
def ProcessServiceUpdates( self, service_identifiers_to_service_updates ):
ClientGUIMixins.ListeningMediaList.ProcessServiceUpdate( self, update )
ClientGUIMixins.ListeningMediaList.ProcessServiceUpdates( self, service_identifiers_to_service_updates )
action = update.GetAction()
service_identifier = update.GetServiceIdentifier()
if action in ( HC.SERVICE_UPDATE_DELETE_PENDING, HC.SERVICE_UPDATE_RESET ):
for ( service_identifier, service_updates ) in service_identifiers_to_service_updates.items():
self._RefitCanvas()
for service_update in service_updates:
( action, row ) = service_update.ToTuple()
if action in ( HC.SERVICE_UPDATE_DELETE_PENDING, HC.SERVICE_UPDATE_RESET ):
self._RefitCanvas()
self._ReblitCanvas()
self._PublishSelectionChange()
self._ReblitCanvas()
self._PublishSelectionChange()
def SetFocussedMedia( self, page_key, media ):
@ -1102,7 +1125,7 @@ class MediaPanelThumbnails( MediaPanel ):
elif command == 'custom_filter': self._CustomFilter()
elif command == 'delete': self._Delete( data )
elif command == 'deselect': self._DeselectAll()
elif command == 'download': wx.GetApp().Write( 'add_downloads', data, self._GetSelectedHashes( CC.DISCRIMINANT_NOT_LOCAL ) )
elif command == 'download': wx.GetApp().Write( 'content_updates', { HC.LOCAL_FILE_SERVICE_IDENTIFIER : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_UPDATE_PENDING, self._GetSelectedHashes( CC.DISCRIMINANT_NOT_LOCAL ) ) ] } )
elif command == 'export': self._ExportFiles()
elif command == 'export special': self._ExportFilesSpecial()
elif command == 'filter': self._Filter()
@ -1145,7 +1168,7 @@ class MediaPanelThumbnails( MediaPanel ):
if t is not None:
if t.GetFileServiceIdentifiersCDPP().HasLocal(): self._FullScreen( t )
elif self._file_service_identifier != HC.COMBINED_FILE_SERVICE_IDENTIFIER: wx.GetApp().Write( 'add_downloads', self._file_service_identifier, t.GetHashes() )
elif self._file_service_identifier != HC.COMBINED_FILE_SERVICE_IDENTIFIER: wx.GetApp().Write( 'content_updates', { HC.LOCAL_FILE_SERVICE_IDENTIFIER : [ HC.ContentUpdate( HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_UPDATE_PENDING, t.GetHashes() ) ] } )
@ -1249,7 +1272,7 @@ class MediaPanelThumbnails( MediaPanel ):
petitioned_phrase = 'all petitioned from'
deleted_phrase = 'all deleted from'
download_phrase = 'download all possible from'
download_phrase = 'download all possible'
upload_phrase = 'upload all possible to'
petition_phrase = 'petition all possible for removal from'
remote_delete_phrase = 'delete all possible from'
@ -1274,7 +1297,7 @@ class MediaPanelThumbnails( MediaPanel ):
petitioned_phrase = 'petitioned from'
deleted_phrase = 'deleted from'
download_phrase = 'download from'
download_phrase = 'download'
upload_phrase = 'upload to'
petition_phrase = 'petition for removal from'
remote_delete_phrase = 'delete from'
@ -1295,29 +1318,31 @@ class MediaPanelThumbnails( MediaPanel ):
# info about the files
def MassUnion( lists ): return { item for item in itertools.chain.from_iterable( lists ) }
all_current_file_service_identifiers = [ service_identifiers.GetCurrentRemote() for service_identifiers in all_service_identifiers ]
current_file_service_identifiers = HC.IntelligentMassIntersect( all_current_file_service_identifiers )
some_current_file_service_identifiers = HC.IntelligentMassUnion( all_current_file_service_identifiers ) - current_file_service_identifiers
some_current_file_service_identifiers = MassUnion( all_current_file_service_identifiers ) - current_file_service_identifiers
all_pending_file_service_identifiers = [ service_identifiers.GetPendingRemote() for service_identifiers in all_service_identifiers ]
pending_file_service_identifiers = HC.IntelligentMassIntersect( all_pending_file_service_identifiers )
some_pending_file_service_identifiers = HC.IntelligentMassUnion( all_pending_file_service_identifiers ) - pending_file_service_identifiers
some_pending_file_service_identifiers = MassUnion( all_pending_file_service_identifiers ) - pending_file_service_identifiers
all_petitioned_file_service_identifiers = [ service_identifiers.GetPetitionedRemote() for service_identifiers in all_service_identifiers ]
petitioned_file_service_identifiers = HC.IntelligentMassIntersect( all_petitioned_file_service_identifiers )
some_petitioned_file_service_identifiers = HC.IntelligentMassUnion( all_petitioned_file_service_identifiers ) - petitioned_file_service_identifiers
some_petitioned_file_service_identifiers = MassUnion( all_petitioned_file_service_identifiers ) - petitioned_file_service_identifiers
all_deleted_file_service_identifiers = [ service_identifiers.GetDeletedRemote() for service_identifiers in all_service_identifiers ]
deleted_file_service_identifiers = HC.IntelligentMassIntersect( all_deleted_file_service_identifiers )
some_deleted_file_service_identifiers = HC.IntelligentMassUnion( all_deleted_file_service_identifiers ) - deleted_file_service_identifiers
some_deleted_file_service_identifiers = MassUnion( all_deleted_file_service_identifiers ) - deleted_file_service_identifiers
# valid commands for the files
@ -1396,7 +1421,7 @@ class MediaPanelThumbnails( MediaPanel ):
if len( selection_downloadable_file_service_identifiers ) > 0 or len( selection_uploadable_file_service_identifiers ) > 0 or len( selection_petitionable_file_service_identifiers ) > 0 or len( selection_deletable_file_service_identifiers ) > 0 or len( selection_modifyable_file_service_identifiers ) > 0:
if len( selection_downloadable_file_service_identifiers ) > 0: AddFileServiceIdentifiersToMenu( menu, selection_downloadable_file_service_identifiers, download_phrase, 'download' )
if len( selection_downloadable_file_service_identifiers ) > 0: menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'download' ), download_phrase )
if len( selection_uploadable_file_service_identifiers ) > 0: AddFileServiceIdentifiersToMenu( menu, selection_uploadable_file_service_identifiers, upload_phrase, 'upload' )
@ -1958,13 +1983,20 @@ class ThumbnailMediaCollection( Thumbnail, ClientGUIMixins.MediaCollection ):
Thumbnail.__init__( self, file_service_identifier )
def ProcessContentUpdate( self, content_update ):
def ProcessContentUpdate( self, service_identifier, content_update ):
ClientGUIMixins.MediaCollection.ProcessContentUpdate( self, content_update )
ClientGUIMixins.MediaCollection.ProcessContentUpdate( self, service_identifier, content_update )
if content_update.GetAction() == HC.CONTENT_UPDATE_ADD and content_update.GetServiceIdentifier() == HC.LOCAL_FILE_SERVICE_IDENTIFIER:
if service_identifier == HC.LOCAL_FILE_SERVICE_IDENTIFIER:
if self.GetDisplayMedia() in self._GetMedia( content_update.GetHashes() ): self.ReloadFromDB()
( data_type, action, row ) = content_update.ToTuple()
if action == HC.CONTENT_UPDATE_ADD:
hashes = row
if self.GetDisplayMedia().GetHash() in hashes: self.ReloadFromDB()
@ -1976,10 +2008,15 @@ class ThumbnailMediaSingleton( Thumbnail, ClientGUIMixins.MediaSingleton ):
Thumbnail.__init__( self, file_service_identifier )
def ProcessContentUpdate( self, content_update ):
def ProcessContentUpdate( self, servce_identifier, content_update ):
ClientGUIMixins.MediaSingleton.ProcessContentUpdate( self, content_update )
ClientGUIMixins.MediaSingleton.ProcessContentUpdate( self, service_identifier, content_update )
if content_update.GetAction() == HC.CONTENT_UPDATE_ADD and content_update.GetServiceIdentifier() == HC.LOCAL_FILE_SERVICE_IDENTIFIER: self.ReloadFromDB()
if service_identifier == HC.LOCAL_FILE_SERVICE_IDENTIFIER:
( data_type, action, row ) = content_update.ToTuple()
if action == HC.CONTENT_UPDATE_ADD: self.ReloadFromDB()

View File

@ -36,7 +36,14 @@ class MediaList():
def _GetFirst( self ): return self._sorted_media[ 0 ]
def _GetHashes( self ): return HC.IntelligentMassUnion( [ media.GetHashes() for media in self._sorted_media ] )
def _GetHashes( self ):
result = set()
for media in self._sorted_media: result.update( media.GetHashes() )
return result
def _GetLast( self ): return self._sorted_media[ -1 ]
@ -217,19 +224,37 @@ class MediaList():
def HasNoMedia( self ): return len( self._sorted_media ) == 0
def ProcessContentUpdate( self, content_update ):
def ProcessContentUpdate( self, service_identifier, content_update ):
action = content_update.GetAction()
service_identifier = content_update.GetServiceIdentifier()
( data_type, action, row ) = content_update.ToTuple()
hashes = content_update.GetHashes()
for media in self._GetMedia( hashes, 'collections' ): media.ProcessContentUpdate( content_update )
for media in self._GetMedia( hashes, 'collections' ): media.ProcessContentUpdate( service_identifier, content_update )
if action == HC.CONTENT_UPDATE_ARCHIVE:
if data_type == HC.CONTENT_DATA_TYPE_FILES:
if HC.SYSTEM_PREDICATE_INBOX in self._predicates:
if action == HC.CONTENT_UPDATE_ARCHIVE:
if HC.SYSTEM_PREDICATE_INBOX in self._predicates:
affected_singleton_media = self._GetMedia( hashes, 'singletons' )
affected_collected_media = [ media for media in self._collected_media if media.HasNoMedia() ]
self._RemoveMedia( affected_singleton_media, affected_collected_media )
elif action == HC.CONTENT_UPDATE_INBOX:
if HC.SYSTEM_PREDICATE_ARCHIVE in self._predicates:
affected_singleton_media = self._GetMedia( hashes, 'singletons' )
affected_collected_media = [ media for media in self._collected_media if media.HasNoMedia() ]
self._RemoveMedia( affected_singleton_media, affected_collected_media )
elif action == HC.CONTENT_UPDATE_DELETE and service_identifier == self._file_service_identifier:
affected_singleton_media = self._GetMedia( hashes, 'singletons' )
affected_collected_media = [ media for media in self._collected_media if media.HasNoMedia() ]
@ -237,38 +262,28 @@ class MediaList():
self._RemoveMedia( affected_singleton_media, affected_collected_media )
elif action == HC.CONTENT_UPDATE_INBOX:
def ProcessContentUpdates( self, service_identifiers_to_content_updates ):
for ( service_identifier, content_updates ) in service_identifiers_to_content_updates.items():
if HC.SYSTEM_PREDICATE_ARCHIVE in self._predicates:
affected_singleton_media = self._GetMedia( hashes, 'singletons' )
affected_collected_media = [ media for media in self._collected_media if media.HasNoMedia() ]
self._RemoveMedia( affected_singleton_media, affected_collected_media )
elif action == HC.CONTENT_UPDATE_DELETE and service_identifier == self._file_service_identifier:
affected_singleton_media = self._GetMedia( hashes, 'singletons' )
affected_collected_media = [ media for media in self._collected_media if media.HasNoMedia() ]
self._RemoveMedia( affected_singleton_media, affected_collected_media )
for content_update in content_updates: self.ProcessContentUpdate( service_identifier, content_update )
def ProcessContentUpdates( self, content_updates ):
def ProcessServiceUpdates( self, service_identifiers_to_service_updates ):
for content_update in content_updates: self.ProcessContentUpdate( content_update )
def ProcessServiceUpdate( self, update ):
action = update.GetAction()
service_identifier = update.GetServiceIdentifier()
if action == HC.SERVICE_UPDATE_DELETE_PENDING: self.DeletePending( service_identifier )
elif action == HC.SERVICE_UPDATE_RESET: self.ResetService( service_identifier )
for ( service_identifier, service_updates ) in service_identifiers_to_service_updates.items():
for service_update in service_updates:
( action, row ) = service_update.ToTuple()
if action == HC.SERVICE_UPDATE_DELETE_PENDING: self.DeletePending( service_identifier )
elif action == HC.SERVICE_UPDATE_RESET: self.ResetService( service_identifier )
def ResetService( self, service_identifier ):
@ -387,7 +402,7 @@ class ListeningMediaList( MediaList ):
MediaList.__init__( self, *args )
HC.pubsub.sub( self, 'ProcessContentUpdates', 'content_updates_gui' )
HC.pubsub.sub( self, 'ProcessServiceUpdate', 'service_update_gui' )
HC.pubsub.sub( self, 'ProcessServiceUpdates', 'service_updates_gui' )
class MediaCollection( MediaList, Media ):
@ -422,7 +437,9 @@ class MediaCollection( MediaList, Media ):
def _RecalcInternals( self ):
self._hashes = HC.IntelligentMassUnion( [ media.GetHashes() for media in self._sorted_media ] )
self._hashes = set()
for media in self._sorted_media: self._hashes.update( media.GetHashes() )
self._archive = True in ( media.HasArchive() for media in self._sorted_media )
self._inbox = True in ( media.HasInbox() for media in self._sorted_media )
@ -472,7 +489,14 @@ class MediaCollection( MediaList, Media ):
def GetHashes( self, discriminant = None, not_uploaded_to = None ):
if discriminant is None and not_uploaded_to is None: return self._hashes
else: return HC.IntelligentMassUnion( [ media.GetHashes( discriminant, not_uploaded_to ) for media in self._sorted_media ] )
else:
result = set()
for media in self._sorted_media: result.update( media.GetHashes( discriminant, not_uploaded_to ) )
return result
def GetHashes( self, discriminant = None, not_uploaded_to = None ):
@ -546,9 +570,9 @@ class MediaCollection( MediaList, Media ):
def IsSizeDefinite( self ): return self._size_definite
def ProcessContentUpdate( self, content_update ):
def ProcessContentUpdate( self, service_identifier, content_update ):
MediaList.ProcessContentUpdate( self, content_update )
MediaList.ProcessContentUpdate( self, service_identifier, content_update )
self._RecalcInternals()
@ -615,7 +639,7 @@ class MediaSingleton( Media ):
def GetPrettyInfo( self ):
( hash, inbox, size, mime, timestamp, width, height, duration, num_frames, num_words, tags_manager, file_service_identifiers, local_ratings, remote_ratings ) = self._media_result.GetInfo()
( hash, inbox, size, mime, timestamp, width, height, duration, num_frames, num_words, tags_manager, file_service_identifiers, local_ratings, remote_ratings ) = self._media_result.ToTuple()
info_string = HC.ConvertIntToBytes( size ) + ' ' + HC.mime_string_lookup[ mime ]

View File

@ -354,7 +354,19 @@ class PageImportURL( PageImport ):
class PagePetitions( PageWithMedia ):
def _InitManagementPanel( self ): self._management_panel = ClientGUIManagement.ManagementPanelPetitions( self._search_preview_split, self, self._page_key, self._file_service_identifier )
def __init__( self, parent, petition_service_identifier ):
self._petition_service_identifier = petition_service_identifier
petition_service_type = petition_service_identifier.GetType()
if petition_service_type in ( HC.LOCAL_FILE, HC.FILE_REPOSITORY ): self._file_service_identifier = self._petition_service_identifier
else: self._file_service_identifier = HC.COMBINED_FILE_SERVICE_IDENTIFIER
PageWithMedia.__init__( self, parent, self._file_service_identifier )
def _InitManagementPanel( self ): self._management_panel = ClientGUIManagement.ManagementPanelPetitions( self._search_preview_split, self, self._page_key, self._file_service_identifier, self._petition_service_identifier )
def _InitMediaPanel( self ): self._media_panel = ClientGUIMedia.MediaPanelNoQuery( self, self._page_key, self._file_service_identifier )

View File

@ -1,6 +1,7 @@
import collections
import httplib
import HydrusPubSub
import itertools
import locale
import os
import Queue
@ -29,8 +30,8 @@ TEMP_DIR = BASE_DIR + os.path.sep + 'temp'
# Misc
NETWORK_VERSION = 9
SOFTWARE_VERSION = 71
NETWORK_VERSION = 10
SOFTWARE_VERSION = 72
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )
@ -46,6 +47,12 @@ repos_or_subs_changed = False
# Enums
CONTENT_DATA_TYPE_MAPPINGS = 0
CONTENT_DATA_TYPE_TAG_SIBLINGS = 1
CONTENT_DATA_TYPE_TAG_PARENTS = 2
CONTENT_DATA_TYPE_FILES = 3
CONTENT_DATA_TYPE_RATINGS = 4
CONTENT_UPDATE_ADD = 0
CONTENT_UPDATE_DELETE = 1
CONTENT_UPDATE_PENDING = 2
@ -57,6 +64,8 @@ CONTENT_UPDATE_ARCHIVE = 7
CONTENT_UPDATE_INBOX = 8
CONTENT_UPDATE_RATING = 9
CONTENT_UPDATE_RATINGS_FILTER = 10
CONTENT_UPDATE_DENY_PEND = 11
CONTENT_UPDATE_DENY_PETITION = 12
GET_DATA = 0
POST_DATA = 1
@ -103,7 +112,7 @@ service_string_lookup[ SERVER_ADMIN ] = 'hydrus server administration'
RATINGS_SERVICES = [ LOCAL_RATING_LIKE, LOCAL_RATING_NUMERICAL, RATING_LIKE_REPOSITORY, RATING_NUMERICAL_REPOSITORY ]
REPOSITORIES = [ TAG_REPOSITORY, FILE_REPOSITORY, RATING_LIKE_REPOSITORY, RATING_NUMERICAL_REPOSITORY ]
RESTRICTED_SERVICES = list( REPOSITORIES ) + [ SERVER_ADMIN, MESSAGE_DEPOT ]
RESTRICTED_SERVICES = ( REPOSITORIES ) + [ SERVER_ADMIN, MESSAGE_DEPOT ]
REMOTE_SERVICES = list( RESTRICTED_SERVICES )
ALL_SERVICES = list( REMOTE_SERVICES ) + [ LOCAL_FILE, LOCAL_TAG, LOCAL_RATING_LIKE, LOCAL_RATING_NUMERICAL ]
@ -148,6 +157,10 @@ SERVICE_INFO_NUM_PENDING_MAPPINGS = 15
SERVICE_INFO_NUM_PETITIONED_MAPPINGS = 16
SERVICE_INFO_NUM_PENDING_FILES = 15
SERVICE_INFO_NUM_PETITIONED_FILES = 16
SERVICE_INFO_NUM_PENDING_TAG_SIBLINGS = 17
SERVICE_INFO_NUM_PETITIONED_TAG_SIBLINGS = 18
SERVICE_INFO_NUM_PENDING_TAG_PARENTS = 19
SERVICE_INFO_NUM_PETITIONED_TAG_PARENTS = 20
SERVICE_UPDATE_ACCOUNT = 0
SERVICE_UPDATE_DELETE_PENDING = 1
@ -156,6 +169,7 @@ SERVICE_UPDATE_NEXT_BEGIN = 3
SERVICE_UPDATE_RESET = 4
SERVICE_UPDATE_REQUEST_MADE = 5
SERVICE_UPDATE_LAST_CHECK = 6
SERVICE_UPDATE_NEWS = 7
ADD = 0
DELETE = 1
@ -412,8 +426,7 @@ repository_requests.append( ( GET, 'num_petitions', RESOLVE_PETITIONS ) )
repository_requests.append( ( GET, 'petition', RESOLVE_PETITIONS ) )
repository_requests.append( ( GET, 'update', GET_DATA ) )
repository_requests.append( ( POST, 'news', GENERAL_ADMIN ) )
repository_requests.append( ( POST, 'petition_denial', RESOLVE_PETITIONS ) )
repository_requests.append( ( POST, 'petitions', ( POST_PETITIONS, RESOLVE_PETITIONS ) ) )
repository_requests.append( ( POST, 'update', POST_DATA ) )
file_repository_requests = list( repository_requests )
file_repository_requests.append( ( GET, 'file', GET_DATA ) )
@ -422,7 +435,6 @@ file_repository_requests.append( ( GET, 'thumbnail', GET_DATA ) )
file_repository_requests.append( ( POST, 'file', POST_DATA ) )
tag_repository_requests = list( repository_requests )
tag_repository_requests.append( ( POST, 'mappings', POST_DATA ) )
message_depot_requests = list( restricted_requests )
message_depot_requests.append( ( GET, 'message', GET_DATA ) )
@ -476,6 +488,10 @@ DEFAULT_OPTIONS[ MESSAGE_DEPOT ][ 'message' ] = 'hydrus message depot'
EVT_PUBSUB = HydrusPubSub.EVT_PUBSUB
pubsub = HydrusPubSub.HydrusPubSub()
def default_dict_list(): return collections.defaultdict( list )
def default_dict_set(): return collections.defaultdict( set )
def BuildKeyToListDict( pairs ):
d = collections.defaultdict( list )
@ -633,6 +649,14 @@ def ConvertShortcutToPrettyShortcut( modifier, key, action ):
return ( modifier, key, action )
def ConvertStatusToPrefix( status ):
if status == CURRENT: return ''
elif status == PENDING: return '(+)'
elif status == PETITIONED: return '(-)'
elif status == DELETED: return '(X)'
elif status == DELETED_PENDING: return '(X+)'
def ConvertTimestampToPrettyAge( timestamp ):
if timestamp == 0 or timestamp is None: return 'unknown age'
@ -895,6 +919,12 @@ def ConvertZoomToPercentage( zoom ):
return pretty_zoom
def GetEmptyDataDict():
data = collections.defaultdict( default_dict_list )
return data
def GetMimeFromPath( filename ):
f = open( filename, 'rb' )
@ -943,21 +973,6 @@ def GetShortcutFromEvent( event ):
return ( modifier, key )
def IntelligentMassUnion( iterables_to_reduce ):
# while I might usually go |= here (for style), it is quicker to use the ugly .update when we want to be quick
# set.update also converts the second argument to a set, if appropriate!
#return reduce( set.union, iterables_to_reduce, set() )
# also: reduce is slower, I think, cause of union rather than update!
answer = set()
for i in iterables_to_reduce: answer.update( i )
return answer
def IntelligentMassIntersect( sets_to_reduce ):
answer = None
@ -986,6 +1001,17 @@ def IsCollection( mime ): return mime in ( APPLICATION_HYDRUS_CLIENT_COLLECTION,
def IsImage( mime ): return mime in ( IMAGE_JPEG, IMAGE_GIF, IMAGE_PNG, IMAGE_BMP )
def MergeKeyToListDicts( key_to_list_dicts ):
result = collections.defaultdict( list )
for key_to_list_dict in key_to_list_dicts:
for ( key, value ) in key_to_list_dict.items(): result[ key ].extend( value )
return result
def SearchEntryMatchesPredicate( search_entry, predicate ):
( predicate_type, info ) = predicate.GetInfo()
@ -1194,7 +1220,7 @@ class AdvancedHTTPConnection():
if server_header is None or service_string not in server_header:
pubsub.pub( 'service_update_db', ServiceUpdate( SERVICE_UPDATE_ACCOUNT, self._service_identifier, GetUnknownAccount() ) )
wx.GetApp().Write( 'service_updates', { self._service_identifier : [ ServiceUpdate( SERVICE_UPDATE_ACCOUNT, GetUnknownAccount() ) ] })
raise WrongServiceTypeException( 'Target was not a ' + service_string + '!' )
@ -1206,9 +1232,9 @@ class AdvancedHTTPConnection():
if request_type == 'GET':
if ( service_type, GET, request_command ) in BANDWIDTH_CONSUMING_REQUESTS: pubsub.pub( 'service_update_db', ServiceUpdate( SERVICE_UPDATE_REQUEST_MADE, self._service_identifier, len( raw_response ) ) )
if ( service_type, GET, request_command ) in BANDWIDTH_CONSUMING_REQUESTS: pubsub.pub( 'service_updates_delayed', { self._service_identifier : [ ServiceUpdate( SERVICE_UPDATE_REQUEST_MADE, len( raw_response ) ) ] } )
elif ( service_type, POST, request_command ) in BANDWIDTH_CONSUMING_REQUESTS: pubsub.pub( 'service_update_db', ServiceUpdate( SERVICE_UPDATE_REQUEST_MADE, self._service_identifier, len( body ) ) )
elif ( service_type, POST, request_command ) in BANDWIDTH_CONSUMING_REQUESTS: pubsub.pub( 'service_updates_delayed', { self._service_identifier : [ ServiceUpdate( SERVICE_UPDATE_REQUEST_MADE, len( body ) ) ] } )
if response.status == 200: return parsed_response
@ -1264,9 +1290,9 @@ class AdvancedHTTPConnection():
if self._service_identifier is not None:
pubsub.pub( 'service_update_db', ServiceUpdate( SERVICE_UPDATE_ERROR, self._service_identifier, parsed_response ) )
wx.GetApp().Write( 'service_updates', { self._service_identifier : [ ServiceUpdate( SERVICE_UPDATE_ERROR, parsed_response ) ] } )
if response.status in ( 401, 426 ): pubsub.pub( 'service_update_db', ServiceUpdate( SERVICE_UPDATE_ACCOUNT, self._service_identifier, GetUnknownAccount() ) )
if response.status in ( 401, 426 ): wx.GetApp().Write( 'service_updates', { self._service_identifier : [ ServiceUpdate( SERVICE_UPDATE_ACCOUNT, GetUnknownAccount() ) ] } )
if response.status == 401: raise PermissionsException( parsed_response )
@ -1511,92 +1537,10 @@ class AccountType( HydrusYAMLBase ):
def HasPermission( self, permission ): return permission in self._permissions
class ClientFilePetitionDenial( HydrusYAMLBase ):
yaml_tag = u'!ClientFilePetitionDenial'
def __init__( self, hashes ):
HydrusYAMLBase.__init__( self )
self._hashes = hashes
def GetInfo( self ): return self._hashes
class ClientFilePetitions( HydrusYAMLBase ):
yaml_tag = u'!ClientFilePetitions'
def __init__( self, petitions ):
HydrusYAMLBase.__init__( self )
self._petitions = petitions
def __iter__( self ): return ( petition for petition in self._petitions )
def __len__( self ): return len( self._petitions )
def GetHashes( self ): return IntelligentMassUnion( [ hashes for ( reason, hashes ) in self._petitions ] )
class ClientMappingPetitionDenial( HydrusYAMLBase ):
yaml_tag = u'!ClientMappingPetitionDenial'
def __init__( self, tag, hashes ):
HydrusYAMLBase.__init__( self )
self._tag = tag
self._hashes = hashes
def GetInfo( self ): return ( self._tag, self._hashes )
class ClientMappingPetitions( HydrusYAMLBase ):
yaml_tag = u'!ClientMappingPetitions'
def __init__( self, petitions, hash_ids_to_hashes ):
HydrusYAMLBase.__init__( self )
self._petitions = petitions
self._hash_ids_to_hashes = hash_ids_to_hashes
def __iter__( self ): return ( ( reason, tag, [ self._hash_ids_to_hashes[ hash_id ] for hash_id in hash_ids ] ) for ( reason, tag, hash_ids ) in self._petitions )
def __len__( self ): return len( self._petitions )
def GetHashes( self ): return self._hash_ids_to_hashes.values()
def GetTags( self ): return [ tag for ( reason, tag, hash_ids ) in self._petitions ]
class ClientMappings( HydrusYAMLBase ):
yaml_tag = u'!ClientMappings'
def __init__( self, mappings, hash_ids_to_hashes ):
HydrusYAMLBase.__init__( self )
self._mappings = mappings
self._hash_ids_to_hashes = hash_ids_to_hashes
def __iter__( self ): return ( ( tag, [ self._hash_ids_to_hashes[ hash_id ] for hash_id in hash_ids ] ) for ( tag, hash_ids ) in self._mappings )
def __len__( self ): return len( self._mappings )
def GetHashes( self ): return self._hash_ids_to_hashes.values()
def GetTags( self ): return [ tag for ( tag, hash_ids ) in self._mappings ]
UNKNOWN_ACCOUNT_TYPE = AccountType( 'unknown account', [], ( None, None ) )
def GetUnknownAccount(): return Account( 0, UNKNOWN_ACCOUNT_TYPE, 0, None, ( 0, 0 ) )
class ClientServiceIdentifier( HydrusYAMLBase ):
yaml_tag = u'!ClientServiceIdentifier'
@ -1630,23 +1574,147 @@ COMBINED_FILE_SERVICE_IDENTIFIER = ClientServiceIdentifier( 'all known files', C
COMBINED_TAG_SERVICE_IDENTIFIER = ClientServiceIdentifier( 'all known tags', COMBINED_TAG, 'all known tags' )
NULL_SERVICE_IDENTIFIER = ClientServiceIdentifier( '', NULL_SERVICE, 'no service' )
class ClientToServerUpdate( HydrusYAMLBase ):
yaml_tag = u'!ClientToServerUpdate'
def __init__( self, content_data, hash_ids_to_hashes ):
HydrusYAMLBase.__init__( self )
# we need to flatten it from a collections.defaultdict to just a normal dict so it can be YAMLised
self._content_data = {}
for data_type in content_data:
self._content_data[ data_type ] = {}
for action in content_data[ data_type ]: self._content_data[ data_type ][ action ] = content_data[ data_type ][ action ]
self._hash_ids_to_hashes = hash_ids_to_hashes
def GetContentUpdates( self, for_client = False ):
data_types = [ CONTENT_DATA_TYPE_FILES, CONTENT_DATA_TYPE_MAPPINGS, CONTENT_DATA_TYPE_TAG_SIBLINGS, CONTENT_DATA_TYPE_TAG_PARENTS ]
actions = [ CONTENT_UPDATE_PENDING, CONTENT_UPDATE_PETITION, CONTENT_UPDATE_DENY_PEND, CONTENT_UPDATE_DENY_PETITION ]
content_updates = []
for ( data_type, action ) in itertools.product( data_types, actions ):
munge_row = lambda row: row
if for_client:
if action == CONTENT_UPDATE_PENDING: new_action = CONTENT_UPDATE_ADD
elif action == CONTENT_UPDATE_PETITION: new_action = CONTENT_UPDATE_DELETE
else: continue
if data_type in ( CONTENT_DATA_TYPE_TAG_SIBLINGS, CONTENT_DATA_TYPE_TAG_PARENTS ) and action in ( CONTENT_UPDATE_PENDING, CONTENT_UPDATE_PETITION ):
munge_row = lambda ( pair, reason ): pair
elif data_type == CONTENT_DATA_TYPE_FILES and action == CONTENT_UPDATE_PETITION:
munge_row = lambda ( hashes, reason ): hashes
elif data_type == CONTENT_DATA_TYPE_MAPPINGS and action == CONTENT_UPDATE_PETITION:
munge_row = lambda ( tag, hashes, reason ): ( tag, hashes )
else: new_action = action
content_updates.extend( [ ContentUpdate( data_type, new_action, munge_row( row ) ) for row in self.GetContentDataIterator( data_type, action ) ] )
return content_updates
def GetHashes( self ): return self._hash_ids_to_hashes.values()
def GetContentDataIterator( self, data_type, action ):
if data_type not in self._content_data or action not in self._content_data[ data_type ]: return ()
data = self._content_data[ data_type ][ action ]
if data_type == CONTENT_DATA_TYPE_FILES:
if action == CONTENT_UPDATE_PETITION: return ( ( { self._hash_ids_to_hashes[ hash_id ] for hash_id in hash_ids }, reason ) for ( hash_ids, reason ) in data )
else: return ( { self._hash_ids_to_hashes[ hash_id ] for hash_id in hash_ids } for hash_ids in ( data, ) )
if data_type == CONTENT_DATA_TYPE_MAPPINGS:
if action == CONTENT_UPDATE_PETITION: return ( ( tag, [ self._hash_ids_to_hashes[ hash_id ] for hash_id in hash_ids ], reason ) for ( tag, hash_ids, reason ) in data )
else: return ( ( tag, [ self._hash_ids_to_hashes[ hash_id ] for hash_id in hash_ids ] ) for ( tag, hash_ids ) in data )
else: return data.__iter__()
def GetTags( self ):
tags = set()
try: tags.update( ( tag for ( tag, hash_ids ) in self._content_data[ CONTENT_DATA_TYPE_MAPPINGS ][ CONTENT_UPDATE_PENDING ] ) )
except: pass
try: tags.update( ( tag for ( tag, hash_ids, reason ) in self._content_data[ CONTENT_DATA_TYPE_MAPPINGS ][ CONTENT_UPDATE_PETITION ] ) )
except: pass
return tags
def IsEmpty( self ):
num_total = 0
for data_type in self._content_data:
for action in self._content_data[ data_type ]: num_total += len( self._content_data[ data_type ][ action ] )
return num_total == 0
class ContentUpdate():
def __init__( self, action, service_identifier, hashes, info = None ):
def __init__( self, data_type, action, row ):
self._data_type = data_type
self._action = action
self._service_identifier = service_identifier
self._hashes = set( hashes )
self._info = info
self._row = row
def GetAction( self ): return self._action
def GetHashes( self ):
if self._data_type == CONTENT_DATA_TYPE_FILES:
if self._action == CONTENT_UPDATE_ADD:
hash = self._row[0]
hashes = set( ( hash, ) )
elif self._action in ( CONTENT_UPDATE_ARCHIVE, CONTENT_UPDATE_DELETE, CONTENT_UPDATE_INBOX, CONTENT_UPDATE_PENDING, CONTENT_UPDATE_RESCIND_PENDING, CONTENT_UPDATE_RESCIND_PETITION ): hashes = self._row
elif self._action == CONTENT_UPDATE_PETITION: ( hashes, reason ) = self._row
elif self._data_type == CONTENT_DATA_TYPE_MAPPINGS:
if self._action == CONTENT_UPDATE_PETITION: ( tag, hashes, reason ) = self._row
else: ( tag, hashes ) = self._row
elif self._data_type in ( CONTENT_DATA_TYPE_TAG_PARENTS, CONTENT_DATA_TYPE_TAG_SIBLINGS ): hashes = set()
if type( hashes ) != set: hashes = set( hashes )
return hashes
def GetHashes( self ): return self._hashes
def GetInfo( self ): return self._info
def GetServiceIdentifier( self ): return self._service_identifier
def ToTuple( self ): return ( self._data_type, self._action, self._row )
class DAEMON( threading.Thread ):
@ -1739,103 +1807,6 @@ class DAEMONWorker( DAEMON ):
def set( self, *args, **kwargs ): self._event.set()
class HydrusUpdate( HydrusYAMLBase ):
yaml_tag = u'!HydrusUpdate'
def __init__( self, news, begin, end ):
HydrusYAMLBase.__init__( self )
self._news = news
self._begin = begin
self._end = end
def GetBegin( self ): return self._begin
def GetEnd( self ): return self._end
def GetNextBegin( self ): return self._end + 1
def GetNews( self ): return [ ( news, timestamp ) for ( news, timestamp ) in self._news ]
def SplitIntoSubUpdates( self ): return [ self ]
class HydrusUpdateFileRepository( HydrusUpdate ):
yaml_tag = u'!HydrusUpdateFileRepository'
def __init__( self, files, deleted_hashes, news, begin, end ):
HydrusUpdate.__init__( self, news, begin, end )
self._files = files
self._deleted_hashes = deleted_hashes
def GetDeletedHashes( self ): return self._deleted_hashes
def GetFiles( self ): return self._files
def GetHashes( self ): return [ hash for ( hash, size, mime, timestamp, width, height, duration, num_frames, num_words ) in self._files ]
class HydrusUpdateTagRepository( HydrusUpdate ):
yaml_tag = u'!HydrusUpdateTagRepository'
def __init__( self, mappings, deleted_mappings, hash_ids_to_hashes, news, begin, end ):
HydrusUpdate.__init__( self, news, begin, end )
self._hash_ids_to_hashes = hash_ids_to_hashes
self._mappings = mappings
self._deleted_mappings = deleted_mappings
def GetDeletedMappings( self ): return ( ( tag, [ self._hash_ids_to_hashes[ hash_id ] for hash_id in hash_ids ] ) for ( tag, hash_ids ) in self._deleted_mappings )
def GetMappings( self ): return ( ( tag, [ self._hash_ids_to_hashes[ hash_id ] for hash_id in hash_ids ] ) for ( tag, hash_ids ) in self._mappings )
def GetTags( self ): return [ tag for ( tag, hash_ids ) in self._mappings ]
def SplitIntoSubUpdates( self ):
updates = [ HydrusUpdateTagRepository( [], [], {}, self._news, self._begin, None ) ]
total_mappings = sum( [ len( hashes ) for ( tag, hashes ) in self._mappings ] )
total_tags = len( self._mappings )
number_updates_to_make = total_mappings / 500
if number_updates_to_make == 0: number_updates_to_make = 1
int_to_split_by = total_tags / number_updates_to_make
if int_to_split_by == 0: int_to_split_by = 1
for i in range( 0, len( self._mappings ), int_to_split_by ):
mappings_subset = self._mappings[ i : i + int_to_split_by ]
updates.append( HydrusUpdateTagRepository( mappings_subset, [], self._hash_ids_to_hashes, [], self._begin, None ) )
for i in range( 0, len( self._deleted_mappings ), int_to_split_by ):
deleted_mappings_subset = self._deleted_mappings[ i : i + int_to_split_by ]
updates.append( HydrusUpdateTagRepository( [], deleted_mappings_subset, self._hash_ids_to_hashes, [], self._begin, None ) )
updates.append( HydrusUpdateTagRepository( [], [], {}, [], self._begin, self._end ) )
return updates
class JobInternal():
yaml_tag = u'!JobInternal'
@ -2157,74 +2128,7 @@ class ResponseContext():
def HasBody( self ): return self._body != ''
def HasFilename( self ): return self._filename is not None
class ServerPetition( HydrusYAMLBase ):
yaml_tag = u'!ServerPetition'
def __init__( self, petitioner_identifier ):
HydrusYAMLBase.__init__( self )
self._petitioner_identifier = petitioner_identifier
def GetPetitionerIdentifier( self ): return self._petitioner_identifier
class ServerFilePetition( ServerPetition ):
yaml_tag = u'!ServerFilePetition'
def __init__( self, petitioner_identifier, reason, hashes ):
ServerPetition.__init__( self, petitioner_identifier )
self._reason = reason
self._hashes = hashes
def GetClientPetition( self ): return ClientFilePetitions( [ ( self._reason, self._hashes ) ] )
def GetClientPetitionDenial( self ): return ClientFilePetitionDenial( self._hashes )
def GetPetitionHashes( self ): return self._hashes
def GetPetitionInfo( self ): return ( self._reason, self._hashes )
def GetPetitionInfoDenial( self ): return ( self._hashes, )
def GetPetitionString( self ): return 'For ' + ConvertIntToPrettyString( len( self._hashes ) ) + ' files:' + os.linesep + os.linesep + self._reason
class ServerMappingPetition( ServerPetition ):
yaml_tag = u'!ServerMappingPetition'
def __init__( self, petitioner_identifier, reason, tag, hashes ):
ServerPetition.__init__( self, petitioner_identifier )
self._reason = reason
self._tag = tag
self._hashes = hashes
def GetClientPetition( self ):
hash_ids_to_hashes = { enum : hash for ( enum, hash ) in enumerate( self._hashes ) }
hash_ids = hash_ids_to_hashes.keys()
return ClientMappingPetitions( [ ( self._reason, self._tag, hash_ids ) ], hash_ids_to_hashes )
def GetClientPetitionDenial( self ): return ClientMappingPetitionDenial( self._tag, self._hashes )
def GetPetitionHashes( self ): return self._hashes
def GetPetitionInfo( self ): return ( self._reason, self._tag, self._hashes )
def GetPetitionString( self ): return 'Tag: ' + self._tag + ' for ' + ConvertIntToPrettyString( len( self._hashes ) ) + ' files.' + os.linesep + os.linesep + 'Reason: ' + self._reason
class ServerServiceIdentifier( HydrusYAMLBase ):
yaml_tag = u'!ServerServiceIdentifier'
@ -2249,18 +2153,229 @@ class ServerServiceIdentifier( HydrusYAMLBase ):
class ServiceUpdate():
def __init__( self, action, service_identifier, info = None ):
def __init__( self, action, row = None ):
self._action = action # make this an enumerated thing, yo
self._service_identifier = service_identifier
self._info = info
self._action = action
self._row = row
def GetAction( self ): return self._action
def ToTuple( self ): return ( self._action, self._row )
class ServerToClientPetition( HydrusYAMLBase ):
def GetInfo( self ): return self._info
yaml_tag = u'!ServerToClientPetition'
def GetServiceIdentifier( self ): return self._service_identifier
def __init__( self, petition_type, action, petitioner_account_identifier, petition_data, reason ):
HydrusYAMLBase.__init__( self )
self._petition_type = petition_type
self._action = action
self._petitioner_account_identifier = petitioner_account_identifier
self._petition_data = petition_data
self._reason = reason
def GetApproval( self, reason = None ):
if reason is None: reason = self._reason
if self._petition_type == CONTENT_DATA_TYPE_FILES: hashes = self._petition_data
elif self._petition_type == CONTENT_DATA_TYPE_MAPPINGS: ( tag, hashes ) = self._petition_data
else: hashes = set()
hash_ids_to_hashes = dict( enumerate( hashes ) )
hash_ids = hash_ids_to_hashes.keys()
content_data = GetEmptyDataDict()
if self._petition_type == CONTENT_DATA_TYPE_FILES: row = ( hash_ids, reason )
elif self._petition_type == CONTENT_DATA_TYPE_MAPPINGS: row = ( tag, hash_ids, reason )
else:
( old, new ) = self._petition_data
row = ( ( old, new ), reason )
content_data[ self._petition_type ][ self._action ].append( row )
return ClientToServerUpdate( content_data, hash_ids_to_hashes )
def GetDenial( self ):
if self._petition_type == CONTENT_DATA_TYPE_FILES: hashes = self._petition_data
elif self._petition_type == CONTENT_DATA_TYPE_MAPPINGS: ( tag, hashes ) = self._petition_data
else: hashes = set()
hash_ids_to_hashes = dict( enumerate( hashes ) )
hash_ids = hash_ids_to_hashes.keys()
if self._petition_type == CONTENT_DATA_TYPE_FILES: row_list = hash_ids
elif self._petition_type == CONTENT_DATA_TYPE_MAPPINGS: row_list = [ ( tag, hash_ids ) ]
else: row_list = [ self._petition_data ]
content_data = GetEmptyDataDict()
if self._action == CONTENT_UPDATE_PENDING: denial_action = CONTENT_UPDATE_DENY_PEND
elif self._action == CONTENT_UPDATE_PETITION: denial_action = CONTENT_UPDATE_DENY_PETITION
content_data[ self._petition_type ][ denial_action ] = row_list
return ClientToServerUpdate( content_data, hash_ids_to_hashes )
def GetHashes( self ):
if self._petition_type == CONTENT_DATA_TYPE_FILES: hashes = self._petition_data
elif self._petition_type == CONTENT_DATA_TYPE_MAPPINGS: ( tag, hashes ) = self._petition_data
else: hashes = set()
return hashes
def GetPetitioner( self ): return self._petitioner_account_identifier
def GetPetitionString( self ):
if self._action == CONTENT_UPDATE_PENDING: action_word = 'Add '
elif self._action == CONTENT_UPDATE_PETITION: action_word = 'Remove '
if self._petition_type == CONTENT_DATA_TYPE_FILES:
hashes = self._petition_data
content_phrase = ConvertIntToPrettyString( len( hashes ) ) + ' files'
elif self._petition_type == CONTENT_DATA_TYPE_MAPPINGS:
( tag, hashes ) = self._petition_data
content_phrase = tag + ' for ' + ConvertIntToPrettyString( len( hashes ) ) + ' files'
elif self._petition_type == CONTENT_DATA_TYPE_TAG_SIBLINGS:
( old_tag, new_tag ) = self._petition_data
content_phrase = ' sibling ' + old_tag + '->' + new_tag
elif self._petition_type == CONTENT_DATA_TYPE_TAG_PARENTS:
( old_tag, new_tag ) = self._petition_data
content_phrase = ' parent ' + old_tag + '->' + new_tag
return action_word + content_phrase + os.linesep + os.linesep + self._reason
class ServerToClientUpdate( HydrusYAMLBase ):
yaml_tag = u'!ServerToClientUpdate'
def __init__( self, service_data, content_data, hash_ids_to_hashes ):
HydrusYAMLBase.__init__( self )
self._service_data = service_data
self._content_data = {}
for data_type in content_data:
self._content_data[ data_type ] = {}
for action in content_data[ data_type ]: self._content_data[ data_type ][ action ] = content_data[ data_type ][ action ]
self._hash_ids_to_hashes = hash_ids_to_hashes
def _GetContentData( data_type, action ):
if data_type in self._content_data and action in self._content_data[ data_type ]: return self._content_data[ data_type ][ action ]
else: return []
def GetContentDataIterator( self, data_type, action ):
if data_type not in self._content_data or action not in self._content_data[ data_type ]: return ()
data = self._content_data[ data_type ][ action ]
if data_type == CONTENT_DATA_TYPE_FILES:
if action == CONTENT_UPDATE_ADD: return ( ( self._hash_ids_to_hashes[ hash_id ], size, mime, timestamp, width, height, duration, num_frames, num_words ) for ( hash_id, size, mime, timestamp, width, height, duration, num_frames, num_words ) in data )
else: return ( { self._hash_ids_to_hashes[ hash_id ] for hash_id in hash_ids } for hash_ids in ( data, ) )
elif data_type == CONTENT_DATA_TYPE_MAPPINGS: return ( ( tag, [ self._hash_ids_to_hashes[ hash_id ] for hash_id in hash_ids ] ) for ( tag, hash_ids ) in data )
else: return data.__iter__()
def GetNumContentUpdates( self ):
num = 0
data_types = [ CONTENT_DATA_TYPE_FILES, CONTENT_DATA_TYPE_MAPPINGS, CONTENT_DATA_TYPE_TAG_SIBLINGS, CONTENT_DATA_TYPE_TAG_PARENTS ]
actions = [ CONTENT_UPDATE_ADD, CONTENT_UPDATE_DELETE ]
for ( data_type, action ) in itertools.product( data_types, actions ):
for row in self.GetContentDataIterator( data_type, action ): num += 1
return num
# this needs work!
# we need a universal content_update for both client and server
def IterateContentUpdates( self ):
data_types = [ CONTENT_DATA_TYPE_FILES, CONTENT_DATA_TYPE_MAPPINGS, CONTENT_DATA_TYPE_TAG_SIBLINGS, CONTENT_DATA_TYPE_TAG_PARENTS ]
actions = [ CONTENT_UPDATE_ADD, CONTENT_UPDATE_DELETE ]
for ( data_type, action ) in itertools.product( data_types, actions ):
for row in self.GetContentDataIterator( data_type, action ): yield ContentUpdate( data_type, action, row )
def IterateServiceUpdates( self ):
service_types = [ SERVICE_UPDATE_NEWS, SERVICE_UPDATE_NEXT_BEGIN ]
for service_type in service_types:
if service_type in self._service_data:
data = self._service_data[ service_type ]
yield ServiceUpdate( service_type, data )
def GetHashes( self ): return set( hash_ids_to_hashes.values() )
def GetTags( self ):
tags = set()
tags.update( ( tag for ( tag, hash_ids ) in self.GetContentDataIterator( CONTENT_DATA_TYPE_MAPPINGS, CURRENT ) ) )
tags.update( ( tag for ( tag, hash_ids ) in self.GetContentDataIterator( CONTENT_DATA_TYPE_MAPPINGS, DELETED ) ) )
tags.update( ( old_tag for ( old_tag, new_tag ) in self.GetContentDataIterator( CONTENT_DATA_TYPE_TAG_SIBLINGS, CURRENT ) ) )
tags.update( ( new_tag for ( old_tag, new_tag ) in self.GetContentDataIterator( CONTENT_DATA_TYPE_TAG_SIBLINGS, CURRENT ) ) )
tags.update( ( old_tag for ( old_tag, new_tag ) in self.GetContentDataIterator( CONTENT_DATA_TYPE_TAG_SIBLINGS, DELETED ) ) )
tags.update( ( new_tag for ( old_tag, new_tag ) in self.GetContentDataIterator( CONTENT_DATA_TYPE_TAG_SIBLINGS, DELETED ) ) )
return tags
def GetServiceData( self, service_type ): return self._service_data[ service_type ]
# sqlite mod
@ -2280,8 +2395,7 @@ sqlite3.register_adapter( bool, int )
sqlite3.register_converter( 'INTEGER_BOOLEAN', integer_boolean_to_bool )
# no converters in this case, since we always want to send the dumped string, not the object, to the network
sqlite3.register_adapter( HydrusUpdateFileRepository, yaml.safe_dump )
sqlite3.register_adapter( HydrusUpdateTagRepository, yaml.safe_dump )
sqlite3.register_adapter( ServerToClientUpdate, yaml.safe_dump )
# Custom Exceptions

View File

@ -1,4 +1,5 @@
import bs4
import collections
import HydrusConstants as HC
import json
import lxml
@ -7,24 +8,23 @@ import urllib
import urlparse
import wx
def ConvertServiceIdentifiersToTagsToContentUpdates( hash, service_identifiers_to_tags ):
def ConvertServiceIdentifiersToTagsToServiceIdentifiersToContentUpdates( hash, service_identifiers_to_tags ):
content_updates = []
hashes = set( ( hash, ) )
service_identifiers_to_content_updates = {}
for ( service_identifier, tags ) in service_identifiers_to_tags.items():
if len( tags ) > 0:
if service_identifier == HC.LOCAL_TAG_SERVICE_IDENTIFIER: action = HC.CONTENT_UPDATE_ADD
else: action = HC.CONTENT_UPDATE_PENDING
edit_log = [ ( action, tag ) for tag in tags ]
content_updates.append( HC.ContentUpdate( HC.CONTENT_UPDATE_EDIT_LOG, service_identifier, ( hash, ), info = edit_log ) )
if service_identifier == HC.LOCAL_TAG_SERVICE_IDENTIFIER: action = HC.CONTENT_UPDATE_ADD
else: action = HC.CONTENT_UPDATE_PENDING
content_updates = [ HC.ContentUpdate( HC.CONTENT_DATA_TYPE_MAPPINGS, action, ( tag, hashes ) ) for tag in tags ]
service_identifiers_to_content_updates[ service_identifier ] = content_updates
return content_updates
return service_identifiers_to_content_updates
def GetDownloader( site_download_type, *args ):

File diff suppressed because it is too large Load Diff