348 lines
12 KiB
Python
348 lines
12 KiB
Python
import typing
|
|
|
|
from hydrus.core import HydrusConstants as HC
|
|
from hydrus.core import HydrusData
|
|
from hydrus.core import HydrusGlobals as HG
|
|
from hydrus.core import HydrusSerialisable
|
|
from hydrus.core import HydrusTime
|
|
|
|
from hydrus.client import ClientConstants as CC
|
|
from hydrus.client import ClientGlobals as CG
|
|
|
|
def FilterOutRedundantMetaServices( list_of_service_keys: typing.List[ bytes ] ):
|
|
|
|
services_manager = CG.client_controller.services_manager
|
|
|
|
special_local_file_service_keys = { CC.TRASH_SERVICE_KEY, CC.COMBINED_LOCAL_MEDIA_SERVICE_KEY, CC.LOCAL_UPDATE_SERVICE_KEY }
|
|
|
|
if len( special_local_file_service_keys.intersection( list_of_service_keys ) ) <= 1:
|
|
|
|
if CC.COMBINED_LOCAL_FILE_SERVICE_KEY in list_of_service_keys:
|
|
|
|
list_of_service_keys.remove( CC.COMBINED_LOCAL_FILE_SERVICE_KEY )
|
|
|
|
|
|
|
|
local_file_service_keys = set( services_manager.GetServiceKeys( ( HC.LOCAL_FILE_DOMAIN, ) ) )
|
|
|
|
if len( local_file_service_keys.intersection( list_of_service_keys ) ) <= 1:
|
|
|
|
if CC.COMBINED_LOCAL_MEDIA_SERVICE_KEY in list_of_service_keys:
|
|
|
|
list_of_service_keys.remove( CC.COMBINED_LOCAL_MEDIA_SERVICE_KEY )
|
|
|
|
|
|
|
|
return list_of_service_keys
|
|
|
|
|
|
def GetPossibleFileDomainServicesInOrder( all_known_files_allowed: bool, only_local_file_domains_allowed: bool ):
|
|
|
|
services_manager = CG.client_controller.services_manager
|
|
|
|
service_types_in_order = [ HC.LOCAL_FILE_DOMAIN ]
|
|
|
|
if not only_local_file_domains_allowed:
|
|
|
|
advanced_mode = CG.client_controller.new_options.GetBoolean( 'advanced_mode' )
|
|
|
|
if len( services_manager.GetServices( ( HC.LOCAL_FILE_DOMAIN, ) ) ) > 1 or advanced_mode:
|
|
|
|
service_types_in_order.append( HC.COMBINED_LOCAL_MEDIA )
|
|
|
|
|
|
service_types_in_order.append( HC.LOCAL_FILE_TRASH_DOMAIN )
|
|
|
|
if advanced_mode:
|
|
|
|
service_types_in_order.append( HC.LOCAL_FILE_UPDATE_DOMAIN )
|
|
|
|
|
|
if advanced_mode:
|
|
|
|
service_types_in_order.append( HC.COMBINED_LOCAL_FILE )
|
|
|
|
service_types_in_order.append( HC.COMBINED_DELETED_FILE )
|
|
|
|
|
|
service_types_in_order.append( HC.FILE_REPOSITORY )
|
|
service_types_in_order.append( HC.IPFS )
|
|
|
|
if all_known_files_allowed:
|
|
|
|
service_types_in_order.append( HC.COMBINED_FILE )
|
|
|
|
|
|
|
|
services = services_manager.GetServices( service_types_in_order )
|
|
|
|
return services
|
|
|
|
|
|
def SortFileServiceKeysNicely( list_of_service_keys ):
|
|
|
|
services_in_nice_order = GetPossibleFileDomainServicesInOrder( False, False )
|
|
|
|
service_keys_in_nice_order = [ service.GetServiceKey() for service in services_in_nice_order ]
|
|
|
|
list_of_service_keys = [ service_key for service_key in service_keys_in_nice_order if service_key in list_of_service_keys ]
|
|
|
|
return list_of_service_keys
|
|
|
|
|
|
def ValidLocalDomainsFilter( service_keys ):
|
|
|
|
return [ service_key for service_key in service_keys if CG.client_controller.services_manager.ServiceExists( service_key ) and CG.client_controller.services_manager.GetServiceType( service_key ) == HC.LOCAL_FILE_DOMAIN ]
|
|
|
|
class LocationContext( HydrusSerialisable.SerialisableBase ):
|
|
|
|
SERIALISABLE_TYPE = HydrusSerialisable.SERIALISABLE_TYPE_LOCATION_CONTEXT
|
|
SERIALISABLE_NAME = 'Location Search Context'
|
|
SERIALISABLE_VERSION = 1
|
|
|
|
def __init__( self, current_service_keys = None, deleted_service_keys = None ):
|
|
|
|
# note this is pretty much a read-only class
|
|
# sometimes we'll run FixMissingServices, but usually only on load and who cares if that fix is propagated around
|
|
# hence no need to duplicate this for every handler, since it won't be changing
|
|
|
|
if current_service_keys is None:
|
|
|
|
current_service_keys = []
|
|
|
|
|
|
if deleted_service_keys is None:
|
|
|
|
deleted_service_keys = []
|
|
|
|
|
|
self.current_service_keys = frozenset( current_service_keys )
|
|
self.deleted_service_keys = frozenset( deleted_service_keys )
|
|
|
|
if self.IsAllKnownFiles():
|
|
|
|
self.current_service_keys = frozenset( [ CC.COMBINED_FILE_SERVICE_KEY ] )
|
|
self.deleted_service_keys = frozenset()
|
|
|
|
|
|
|
|
def __eq__( self, other ):
|
|
|
|
if isinstance( other, LocationContext ):
|
|
|
|
return self.__hash__() == other.__hash__()
|
|
|
|
|
|
return NotImplemented
|
|
|
|
|
|
def __hash__( self ):
|
|
|
|
# works because frozenset
|
|
return ( self.current_service_keys, self.deleted_service_keys ).__hash__()
|
|
|
|
|
|
def _GetSerialisableInfo( self ):
|
|
|
|
serialisable_current_service_keys = [ service_key.hex() for service_key in self.current_service_keys ]
|
|
serialisable_deleted_service_keys = [ service_key.hex() for service_key in self.deleted_service_keys ]
|
|
|
|
return ( serialisable_current_service_keys, serialisable_deleted_service_keys )
|
|
|
|
|
|
def _InitialiseFromSerialisableInfo( self, serialisable_info ):
|
|
|
|
( serialisable_current_service_keys, serialisable_deleted_service_keys ) = serialisable_info
|
|
|
|
self.current_service_keys = frozenset( { bytes.fromhex( service_key ) for service_key in serialisable_current_service_keys } )
|
|
self.deleted_service_keys = frozenset( { bytes.fromhex( service_key ) for service_key in serialisable_deleted_service_keys } )
|
|
|
|
|
|
def ClearSurplusLocalFilesServices( self, service_type_func: typing.Callable ):
|
|
# if we have combined local files, then we don't need specific local domains
|
|
|
|
if CC.COMBINED_LOCAL_FILE_SERVICE_KEY in self.current_service_keys:
|
|
|
|
self.current_service_keys = frozenset( ( service_key for service_key in self.current_service_keys if service_type_func( service_key ) not in HC.FILE_SERVICES_COVERED_BY_COMBINED_LOCAL_FILE ) )
|
|
|
|
|
|
if CC.COMBINED_LOCAL_FILE_SERVICE_KEY in self.deleted_service_keys:
|
|
|
|
self.deleted_service_keys = frozenset( ( service_key for service_key in self.deleted_service_keys if service_type_func( service_key ) not in HC.FILE_SERVICES_COVERED_BY_COMBINED_LOCAL_FILE ) )
|
|
|
|
|
|
if CC.COMBINED_LOCAL_MEDIA_SERVICE_KEY in self.current_service_keys:
|
|
|
|
self.current_service_keys = frozenset( ( service_key for service_key in self.current_service_keys if service_type_func( service_key ) not in HC.FILE_SERVICES_COVERED_BY_COMBINED_LOCAL_MEDIA ) )
|
|
|
|
|
|
if CC.COMBINED_LOCAL_MEDIA_SERVICE_KEY in self.deleted_service_keys:
|
|
|
|
self.deleted_service_keys = frozenset( ( service_key for service_key in self.deleted_service_keys if service_type_func( service_key ) not in HC.FILE_SERVICES_COVERED_BY_COMBINED_LOCAL_MEDIA ) )
|
|
|
|
|
|
|
|
def FixMissingServices( self, services_exist_func: typing.Callable ) -> bool:
|
|
|
|
prev_len = len( self.current_service_keys ) + len( self.deleted_service_keys )
|
|
|
|
self.current_service_keys = frozenset( services_exist_func( self.current_service_keys ) )
|
|
self.deleted_service_keys = frozenset( services_exist_func( self.deleted_service_keys ) )
|
|
|
|
post_len = len( self.current_service_keys ) + len( self.deleted_service_keys )
|
|
|
|
some_removed = prev_len != post_len
|
|
|
|
return some_removed
|
|
|
|
|
|
def GetCoveringCurrentFileServiceKeys( self ):
|
|
|
|
file_location_is_cross_referenced = not ( self.IsAllKnownFiles() or self.IncludesDeleted() )
|
|
|
|
file_service_keys = list( self.current_service_keys )
|
|
|
|
if self.IncludesDeleted():
|
|
|
|
file_service_keys.append( CC.COMBINED_DELETED_FILE_SERVICE_KEY )
|
|
|
|
|
|
return ( file_service_keys, file_location_is_cross_referenced )
|
|
|
|
|
|
def GetDeletedInverse( self ):
|
|
|
|
inverse = self.Duplicate()
|
|
|
|
a = inverse.current_service_keys
|
|
inverse.current_service_keys = inverse.deleted_service_keys
|
|
inverse.deleted_service_keys = a
|
|
|
|
return inverse
|
|
|
|
|
|
def GetStatusesAndServiceKeysList( self ):
|
|
|
|
statuses_and_service_keys = [ ( HC.CONTENT_STATUS_CURRENT, service_key ) for service_key in self.current_service_keys ]
|
|
statuses_and_service_keys.extend( [ ( HC.CONTENT_STATUS_DELETED, service_key ) for service_key in self.deleted_service_keys ] )
|
|
|
|
return statuses_and_service_keys
|
|
|
|
|
|
def IncludesCurrent( self ):
|
|
|
|
return len( self.current_service_keys ) > 0
|
|
|
|
|
|
def IncludesDeleted( self ):
|
|
|
|
return len( self.deleted_service_keys ) > 0
|
|
|
|
|
|
def IsAllKnownFiles( self ):
|
|
|
|
return CC.COMBINED_FILE_SERVICE_KEY in self.current_service_keys
|
|
|
|
|
|
def IsAllLocalFiles( self ):
|
|
|
|
return self.IsOneDomain() and CC.COMBINED_LOCAL_FILE_SERVICE_KEY in self.current_service_keys
|
|
|
|
|
|
def IsAllMediaFiles( self ):
|
|
|
|
return self.IsOneDomain() and CC.COMBINED_LOCAL_MEDIA_SERVICE_KEY in self.current_service_keys
|
|
|
|
|
|
def IsEmpty( self ):
|
|
|
|
return len( self.current_service_keys ) + len( self.deleted_service_keys ) == 0
|
|
|
|
|
|
def IsOneDomain( self ):
|
|
|
|
return len( self.current_service_keys ) + len( self.deleted_service_keys ) == 1
|
|
|
|
|
|
def LimitToServiceTypes( self, service_type_func: typing.Callable, service_types ):
|
|
|
|
self.current_service_keys = frozenset( ( service_key for service_key in self.current_service_keys if service_type_func( service_key ) in service_types ) )
|
|
|
|
self.deleted_service_keys = frozenset( ( service_key for service_key in self.deleted_service_keys if service_type_func( service_key ) in service_types ) )
|
|
|
|
|
|
def ToString( self, name_method ):
|
|
|
|
# this probably needs some params for 'short string' and stuff later on
|
|
|
|
if self.IsEmpty():
|
|
|
|
return 'nothing'
|
|
|
|
|
|
if self.IncludesCurrent() and self.IncludesDeleted():
|
|
|
|
if self.current_service_keys == self.deleted_service_keys:
|
|
|
|
prefix = 'current and deleted files of '
|
|
|
|
else:
|
|
|
|
prefix = 'a mix of current and deleted files of '
|
|
|
|
|
|
elif self.IncludesDeleted():
|
|
|
|
prefix = 'deleted files of '
|
|
|
|
else:
|
|
|
|
prefix = ''
|
|
|
|
|
|
if self.current_service_keys == self.deleted_service_keys:
|
|
|
|
service_keys_to_consider = self.current_service_keys
|
|
|
|
else:
|
|
|
|
service_keys_to_consider = self.current_service_keys.union( self.deleted_service_keys )
|
|
|
|
|
|
if len( service_keys_to_consider ) <= 2:
|
|
|
|
service_strings = sorted( ( name_method( service_key ) for service_key in service_keys_to_consider ) )
|
|
|
|
service_string = ', '.join( service_strings )
|
|
|
|
else:
|
|
|
|
service_string = '{} services'.format( HydrusData.ToHumanInt( len( service_keys_to_consider ) ) )
|
|
|
|
|
|
return prefix + service_string
|
|
|
|
|
|
def ToDictForAPI( self ):
|
|
|
|
return {
|
|
'current_service_keys' : [ service_key.hex() for service_key in self.current_service_keys ],
|
|
'deleted_service_keys' : [ service_key.hex() for service_key in self.deleted_service_keys ]
|
|
}
|
|
|
|
|
|
@staticmethod
|
|
def STATICCreateAllCurrent( current_service_keys ) -> "LocationContext":
|
|
|
|
return LocationContext( current_service_keys, [] )
|
|
|
|
|
|
@staticmethod
|
|
def STATICCreateSimple( file_service_key ) -> "LocationContext":
|
|
|
|
return LocationContext( [ file_service_key ], [] )
|
|
|
|
|
|
HydrusSerialisable.SERIALISABLE_TYPES_TO_OBJECT_TYPES[ HydrusSerialisable.SERIALISABLE_TYPE_LOCATION_CONTEXT ] = LocationContext
|
|
|