<s> import ClientDefaults <EOL> import ClientFiles <EOL> import ClientNetworking <EOL> import ClientRendering <EOL> import HydrusConstants as HC <EOL> import HydrusExceptions <EOL> import HydrusFileHandling <EOL> import HydrusImageHandling <EOL> import HydrusPaths <EOL> import HydrusSessions <EOL> import itertools <EOL> import os <EOL> import random <EOL> import Queue <EOL> import shutil <EOL> import threading <EOL> import time <EOL> import urllib <EOL> import wx <EOL> import HydrusData <EOL> import ClientData <EOL> import ClientConstants as CC <EOL> import HydrusGlobals <EOL> import collections <EOL> import HydrusTags <EOL> import itertools <EOL> import ClientSearch <EOL> def BuildServiceKeysToChildrenToParents ( service_keys_to_simple_children_to_parents ) : <EOL> def AddParents ( simple_children_to_parents , children_to_parents , child , parents ) : <EOL> for parent in parents : <EOL> if parent not in children_to_parents [ child ] : <EOL> children_to_parents [ child ] . append ( parent ) <EOL> if parent in simple_children_to_parents : <EOL> grandparents = simple_children_to_parents [ parent ] <EOL> AddParents ( simple_children_to_parents , children_to_parents , child , grandparents ) <EOL> service_keys_to_children_to_parents = collections . defaultdict ( HydrusData . default_dict_list ) <EOL> for ( service_key , simple_children_to_parents ) in service_keys_to_simple_children_to_parents . items ( ) : <EOL> children_to_parents = service_keys_to_children_to_parents [ service_key ] <EOL> for ( child , parents ) in simple_children_to_parents . items ( ) : <EOL> AddParents ( simple_children_to_parents , children_to_parents , child , parents ) <EOL> return service_keys_to_children_to_parents <EOL> def BuildServiceKeysToSimpleChildrenToParents ( service_keys_to_pairs_flat ) : <EOL> service_keys_to_simple_children_to_parents = collections . defaultdict ( HydrusData . default_dict_set ) <EOL> for ( service_key , pairs ) in service_keys_to_pairs_flat . items ( ) : <EOL> service_keys_to_simple_children_to_parents [ service_key ] = BuildSimpleChildrenToParents ( pairs ) <EOL> return service_keys_to_simple_children_to_parents <EOL> def BuildSimpleChildrenToParents ( pairs ) : <EOL> simple_children_to_parents = HydrusData . default_dict_set ( ) <EOL> for ( child , parent ) in pairs : <EOL> if child == parent : continue <EOL> if LoopInSimpleChildrenToParents ( simple_children_to_parents , child , parent ) : continue <EOL> simple_children_to_parents [ child ] . add ( parent ) <EOL> return simple_children_to_parents <EOL> def CollapseTagSiblingChains ( processed_siblings ) : <EOL> siblings = { } <EOL> for ( old_tag , new_tag ) in processed_siblings . items ( ) : <EOL> if new_tag in siblings : <EOL> siblings [ old_tag ] = siblings [ new_tag ] <EOL> else : <EOL> while new_tag in processed_siblings : new_tag = processed_siblings [ new_tag ] <EOL> siblings [ old_tag ] = new_tag <EOL> reverse_lookup = collections . defaultdict ( list ) <EOL> for ( old_tag , new_tag ) in siblings . items ( ) : <EOL> reverse_lookup [ new_tag ] . append ( old_tag ) <EOL> return ( siblings , reverse_lookup ) <EOL> def CombineTagSiblingPairs ( service_keys_to_statuses_to_pairs ) : <EOL> processed_siblings = { } <EOL> current_deleted_pairs = set ( ) <EOL> for ( service_key , statuses_to_pairs ) in service_keys_to_statuses_to_pairs . items ( ) : <EOL> pairs = statuses_to_pairs [ HC . CURRENT ] . union ( statuses_to_pairs [ HC . PENDING ] ) <EOL> for ( old , new ) in pairs : <EOL> if old == new : continue <EOL> if old not in processed_siblings : <EOL> next_new = new <EOL> we_have_a_loop = False <EOL> while next_new in processed_siblings : <EOL> next_new = processed_siblings [ next_new ] <EOL> if next_new == old : <EOL> we_have_a_loop = True <EOL> break <EOL> if not we_have_a_loop : processed_siblings [ old ] = new <EOL> return processed_siblings <EOL> def LoopInSimpleChildrenToParents ( simple_children_to_parents , child , parent ) : <EOL> potential_loop_paths = { parent } <EOL> while len ( potential_loop_paths . intersection ( simple_children_to_parents . keys ( ) ) ) > <NUM_LIT:0> : <EOL> new_potential_loop_paths = set ( ) <EOL> for potential_loop_path in potential_loop_paths . intersection ( simple_children_to_parents . keys ( ) ) : <EOL> new_potential_loop_paths . update ( simple_children_to_parents [ potential_loop_path ] ) <EOL> potential_loop_paths = new_potential_loop_paths <EOL> if child in potential_loop_paths : return True <EOL> return False <EOL> class ClientFilesManager ( object ) : <EOL> def __init__ ( self , controller ) : <EOL> self . _controller = controller <EOL> self . _lock = threading . Lock ( ) <EOL> self . _prefixes_to_locations = { } <EOL> self . _bad_error_occured = False <EOL> self . _Reinit ( ) <EOL> def _GetLocation ( self , hash ) : <EOL> hash_encoded = hash . encode ( '<STR_LIT>' ) <EOL> prefix = hash_encoded [ : <NUM_LIT:2> ] <EOL> location = self . _prefixes_to_locations [ prefix ] <EOL> return location <EOL> def _GetRecoverTuple ( self ) : <EOL> paths = { path for path in self . _prefixes_to_locations . values ( ) } <EOL> for path in paths : <EOL> for prefix in HydrusData . IterateHexPrefixes ( ) : <EOL> correct_path = self . _prefixes_to_locations [ prefix ] <EOL> if path != correct_path and os . path . exists ( os . path . join ( path , prefix ) ) : <EOL> return ( prefix , path , correct_path ) <EOL> return None <EOL> def _GetRebalanceTuple ( self ) : <EOL> paths_to_ideal_weights = self . _controller . GetNewOptions ( ) . GetClientFilesLocationsToIdealWeights ( ) <EOL> total_weight = sum ( paths_to_ideal_weights . values ( ) ) <EOL> paths_to_normalised_ideal_weights = { path : weight / total_weight for ( path , weight ) in paths_to_ideal_weights . items ( ) } <EOL> current_paths_to_normalised_weights = collections . defaultdict ( lambda : <NUM_LIT:0> ) <EOL> for ( prefix , path ) in self . _prefixes_to_locations . items ( ) : <EOL> current_paths_to_normalised_weights [ path ] += <NUM_LIT:1.0> / <NUM_LIT> <EOL> for path in current_paths_to_normalised_weights . keys ( ) : <EOL> if path not in paths_to_normalised_ideal_weights : <EOL> paths_to_normalised_ideal_weights [ path ] = <NUM_LIT:0.0> <EOL> overweight_paths = [ ] <EOL> underweight_paths = [ ] <EOL> for ( path , ideal_weight ) in paths_to_normalised_ideal_weights . items ( ) : <EOL> if path in current_paths_to_normalised_weights : <EOL> current_weight = current_paths_to_normalised_weights [ path ] <EOL> if current_weight < ideal_weight : <EOL> underweight_paths . append ( path ) <EOL> elif current_weight >= ideal_weight + <NUM_LIT:1.0> / <NUM_LIT> : <EOL> overweight_paths . append ( path ) <EOL> else : <EOL> underweight_paths . append ( path ) <EOL> if len ( underweight_paths ) == <NUM_LIT:0> or len ( overweight_paths ) == <NUM_LIT:0> : <EOL> return None <EOL> else : <EOL> overweight_path = overweight_paths . pop ( <NUM_LIT:0> ) <EOL> underweight_path = underweight_paths . pop ( <NUM_LIT:0> ) <EOL> prefixes_and_paths = self . _prefixes_to_locations . items ( ) <EOL> random . shuffle ( prefixes_and_paths ) <EOL> for ( prefix , path ) in prefixes_and_paths : <EOL> if path == overweight_path : <EOL> return ( prefix , overweight_path , underweight_path ) <EOL> def _IterateAllFilePaths ( self ) : <EOL> for ( prefix , location ) in self . _prefixes_to_locations . items ( ) : <EOL> dir = os . path . join ( location , prefix ) <EOL> next_filenames = os . listdir ( dir ) <EOL> for filename in next_filenames : <EOL> yield os . path . join ( dir , filename ) <EOL> def _Reinit ( self ) : <EOL> self . _prefixes_to_locations = self . _controller . Read ( '<STR_LIT>' ) <EOL> for ( prefix , location ) in self . _prefixes_to_locations . items ( ) : <EOL> if os . path . exists ( location ) : <EOL> dir = os . path . join ( location , prefix ) <EOL> if not os . path . exists ( dir ) : <EOL> HydrusData . DebugPrint ( '<STR_LIT>' + dir + '<STR_LIT>' ) <EOL> os . makedirs ( dir ) <EOL> else : <EOL> self . _bad_error_occured = True <EOL> HydrusData . DebugPrint ( '<STR_LIT>' + location + '<STR_LIT>' ) <EOL> def GetExpectedFilePath ( self , hash , mime ) : <EOL> with self . _lock : <EOL> location = self . _GetLocation ( hash ) <EOL> return ClientFiles . GetExpectedFilePath ( location , hash , mime ) <EOL> def GetFilePath ( self , hash , mime = None ) : <EOL> with self . _lock : <EOL> location = self . _GetLocation ( hash ) <EOL> return ClientFiles . GetFilePath ( location , hash , mime ) <EOL> def IterateAllFileHashes ( self ) : <EOL> with self . _lock : <EOL> for path in self . _IterateAllFilePaths ( ) : <EOL> ( base , filename ) = os . path . split ( path ) <EOL> result = filename . split ( '<STR_LIT:.>' , <NUM_LIT:1> ) <EOL> if len ( result ) != <NUM_LIT:2> : continue <EOL> ( hash_encoded , ext ) = result <EOL> try : hash = hash_encoded . decode ( '<STR_LIT>' ) <EOL> except TypeError : continue <EOL> yield hash <EOL> def IterateAllFilePaths ( self ) : <EOL> with self . _lock : <EOL> for path in self . _IterateAllFilePaths ( ) : <EOL> yield path <EOL> def Rebalance ( self , partial = True , stop_time = None ) : <EOL> if self . _bad_error_occured : <EOL> return <EOL> with self . _lock : <EOL> rebalance_tuple = self . _GetRebalanceTuple ( ) <EOL> while rebalance_tuple is not None : <EOL> ( prefix , overweight_path , underweight_path ) = rebalance_tuple <EOL> text = '<STR_LIT>' + prefix + '<STR_LIT>' + overweight_path + '<STR_LIT>' + underweight_path <EOL> if partial : <EOL> HydrusData . Print ( text ) <EOL> else : <EOL> self . _controller . pub ( '<STR_LIT>' , text ) <EOL> HydrusData . ShowText ( text ) <EOL> self . _controller . Write ( '<STR_LIT>' , prefix , overweight_path , underweight_path ) <EOL> self . _Reinit ( ) <EOL> if partial : <EOL> break <EOL> if stop_time is not None and HydrusData . TimeHasPassed ( stop_time ) : <EOL> return <EOL> rebalance_tuple = self . _GetRebalanceTuple ( ) <EOL> recover_tuple = self . _GetRecoverTuple ( ) <EOL> while recover_tuple is not None : <EOL> ( prefix , incorrect_path , correct_path ) = recover_tuple <EOL> text = '<STR_LIT>' + prefix + '<STR_LIT>' + incorrect_path + '<STR_LIT>' + correct_path <EOL> if partial : <EOL> HydrusData . Print ( text ) <EOL> else : <EOL> self . _controller . pub ( '<STR_LIT>' , text ) <EOL> HydrusData . ShowText ( text ) <EOL> full_incorrect_path = os . path . join ( incorrect_path , prefix ) <EOL> full_correct_path = os . path . join ( correct_path , prefix ) <EOL> HydrusPaths . CopyAndMergeTree ( full_incorrect_path , full_correct_path ) <EOL> try : HydrusPaths . RecyclePath ( full_incorrect_path ) <EOL> except : <EOL> HydrusData . ShowText ( '<STR_LIT>' + full_incorrect_path + '<STR_LIT>' ) <EOL> return <EOL> if partial : <EOL> break <EOL> if stop_time is not None and HydrusData . TimeHasPassed ( stop_time ) : <EOL> return <EOL> recover_tuple = self . _GetRecoverTuple ( ) <EOL> if not partial : <EOL> HydrusData . ShowText ( '<STR_LIT>' ) <EOL> def TestLocations ( self ) : <EOL> with self . _lock : <EOL> locations = set ( self . _prefixes_to_locations . values ( ) ) <EOL> for location in locations : <EOL> if not os . path . exists ( location ) : <EOL> self . _bad_error_occured = True <EOL> HydrusData . ShowText ( '<STR_LIT>' + location + '<STR_LIT>' ) <EOL> class DataCache ( object ) : <EOL> def __init__ ( self , controller , cache_size_key ) : <EOL> self . _controller = controller <EOL> self . _cache_size_key = cache_size_key <EOL> self . _keys_to_data = { } <EOL> self . _keys_fifo = [ ] <EOL> self . _total_estimated_memory_footprint = <NUM_LIT:0> <EOL> self . _lock = threading . Lock ( ) <EOL> wx . CallLater ( <NUM_LIT> * <NUM_LIT:1000> , self . MaintainCache ) <EOL> def _DeleteItem ( self ) : <EOL> ( deletee_key , last_access_time ) = self . _keys_fifo . pop ( <NUM_LIT:0> ) <EOL> deletee_data = self . _keys_to_data [ deletee_key ] <EOL> del self . _keys_to_data [ deletee_key ] <EOL> self . _RecalcMemoryUsage ( ) <EOL> def _RecalcMemoryUsage ( self ) : <EOL> self . _total_estimated_memory_footprint = sum ( ( data . GetEstimatedMemoryFootprint ( ) for data in self . _keys_to_data . values ( ) ) ) <EOL> def Clear ( self ) : <EOL> with self . _lock : <EOL> self . _keys_to_data = { } <EOL> self . _keys_fifo = [ ] <EOL> self . _total_estimated_memory_footprint = <NUM_LIT:0> <EOL> def AddData ( self , key , data ) : <EOL> with self . _lock : <EOL> if key not in self . _keys_to_data : <EOL> options = self . _controller . GetOptions ( ) <EOL> while self . _total_estimated_memory_footprint > options [ self . _cache_size_key ] : <EOL> self . _DeleteItem ( ) <EOL> self . _keys_to_data [ key ] = data <EOL> self . _keys_fifo . append ( ( key , HydrusData . GetNow ( ) ) ) <EOL> self . _RecalcMemoryUsage ( ) <EOL> def GetData ( self , key ) : <EOL> with self . _lock : <EOL> if key not in self . _keys_to_data : <EOL> raise Exception ( '<STR_LIT>' + HydrusData . ToUnicode ( key ) + '<STR_LIT>' ) <EOL> for ( i , ( fifo_key , last_access_time ) ) in enumerate ( self . _keys_fifo ) : <EOL> if fifo_key == key : <EOL> del self . _keys_fifo [ i ] <EOL> break <EOL> self . _keys_fifo . append ( ( key , HydrusData . GetNow ( ) ) ) <EOL> return self . _keys_to_data [ key ] <EOL> def HasData ( self , key ) : <EOL> with self . _lock : <EOL> return key in self . _keys_to_data <EOL> def MaintainCache ( self ) : <EOL> with self . _lock : <EOL> while True : <EOL> if len ( self . _keys_fifo ) == <NUM_LIT:0> : <EOL> break <EOL> else : <EOL> ( key , last_access_time ) = self . _keys_fifo [ <NUM_LIT:0> ] <EOL> if HydrusData . TimeHasPassed ( last_access_time + <NUM_LIT> ) : <EOL> self . _DeleteItem ( ) <EOL> else : <EOL> break <EOL> wx . CallLater ( <NUM_LIT> * <NUM_LIT:1000> , self . MaintainCache ) <EOL> class LocalBooruCache ( object ) : <EOL> def __init__ ( self , controller ) : <EOL> self . _controller = controller <EOL> self . _lock = threading . Lock ( ) <EOL> self . _RefreshShares ( ) <EOL> self . _controller . sub ( self , '<STR_LIT>' , '<STR_LIT>' ) <EOL> self . _controller . sub ( self , '<STR_LIT>' , '<STR_LIT>' ) <EOL> def _CheckDataUsage ( self ) : <EOL> info = self . _local_booru_service . GetInfo ( ) <EOL> max_monthly_data = info [ '<STR_LIT>' ] <EOL> used_monthly_data = info [ '<STR_LIT>' ] <EOL> if max_monthly_data is not None and used_monthly_data > max_monthly_data : raise HydrusExceptions . ForbiddenException ( '<STR_LIT>' ) <EOL> def _CheckFileAuthorised ( self , share_key , hash ) : <EOL> self . _CheckShareAuthorised ( share_key ) <EOL> info = self . _GetInfo ( share_key ) <EOL> if hash not in info [ '<STR_LIT>' ] : raise HydrusExceptions . NotFoundException ( '<STR_LIT>' ) <EOL> def _CheckShareAuthorised ( self , share_key ) : <EOL> self . _CheckDataUsage ( ) <EOL> info = self . _GetInfo ( share_key ) <EOL> timeout = info [ '<STR_LIT>' ] <EOL> if timeout is not None and HydrusData . TimeHasPassed ( timeout ) : raise HydrusExceptions . ForbiddenException ( '<STR_LIT>' ) <EOL> def _GetInfo ( self , share_key ) : <EOL> try : info = self . _keys_to_infos [ share_key ] <EOL> except : raise HydrusExceptions . NotFoundException ( '<STR_LIT>' ) <EOL> if info is None : <EOL> info = self . _controller . Read ( '<STR_LIT>' , share_key ) <EOL> hashes = info [ '<STR_LIT>' ] <EOL> info [ '<STR_LIT>' ] = set ( hashes ) <EOL> media_results = self . _controller . Read ( '<STR_LIT>' , CC . LOCAL_FILE_SERVICE_KEY , hashes ) <EOL> info [ '<STR_LIT>' ] = media_results <EOL> hashes_to_media_results = { media_result . GetHash ( ) : media_result for media_result in media_results } <EOL> info [ '<STR_LIT>' ] = hashes_to_media_results <EOL> self . _keys_to_infos [ share_key ] = info <EOL> return info <EOL> def _RefreshShares ( self ) : <EOL> self . _local_booru_service = self . _controller . GetServicesManager ( ) . GetService ( CC . LOCAL_BOORU_SERVICE_KEY ) <EOL> self . _keys_to_infos = { } <EOL> share_keys = self . _controller . Read ( '<STR_LIT>' ) <EOL> for share_key in share_keys : self . _keys_to_infos [ share_key ] = None <EOL> def CheckShareAuthorised ( self , share_key ) : <EOL> with self . _lock : self . _CheckShareAuthorised ( share_key ) <EOL> def CheckFileAuthorised ( self , share_key , hash ) : <EOL> with self . _lock : self . _CheckFileAuthorised ( share_key , hash ) <EOL> def GetGalleryInfo ( self , share_key ) : <EOL> with self . _lock : <EOL> self . _CheckShareAuthorised ( share_key ) <EOL> info = self . _GetInfo ( share_key ) <EOL> name = info [ '<STR_LIT:name>' ] <EOL> text = info [ '<STR_LIT:text>' ] <EOL> timeout = info [ '<STR_LIT>' ] <EOL> media_results = info [ '<STR_LIT>' ] <EOL> return ( name , text , timeout , media_results ) <EOL> def GetMediaResult ( self , share_key , hash ) : <EOL> with self . _lock : <EOL> info = self . _GetInfo ( share_key ) <EOL> media_result = info [ '<STR_LIT>' ] [ hash ] <EOL> return media_result <EOL> def GetPageInfo ( self , share_key , hash ) : <EOL> with self . _lock : <EOL> self . _CheckFileAuthorised ( share_key , hash ) <EOL> info = self . _GetInfo ( share_key ) <EOL> name = info [ '<STR_LIT:name>' ] <EOL> text = info [ '<STR_LIT:text>' ] <EOL> timeout = info [ '<STR_LIT>' ] <EOL> media_result = info [ '<STR_LIT>' ] [ hash ] <EOL> return ( name , text , timeout , media_result ) <EOL> def RefreshShares ( self ) : <EOL> with self . _lock : <EOL> self . _RefreshShares ( ) <EOL> class HydrusSessionManager ( object ) : <EOL> def __init__ ( self , controller ) : <EOL> self . _controller = controller <EOL> existing_sessions = self . _controller . Read ( '<STR_LIT>' ) <EOL> self . _service_keys_to_sessions = { service_key : ( session_key , expires ) for ( service_key , session_key , expires ) in existing_sessions } <EOL> self . _lock = threading . Lock ( ) <EOL> def DeleteSessionKey ( self , service_key ) : <EOL> with self . _lock : <EOL> self . _controller . Write ( '<STR_LIT>' , service_key ) <EOL> if service_key in self . _service_keys_to_sessions : <EOL> del self . _service_keys_to_sessions [ service_key ] <EOL> def GetSessionKey ( self , service_key ) : <EOL> now = HydrusData . GetNow ( ) <EOL> with self . _lock : <EOL> if service_key in self . _service_keys_to_sessions : <EOL> ( session_key , expires ) = self . _service_keys_to_sessions [ service_key ] <EOL> if now + <NUM_LIT> > expires : del self . _service_keys_to_sessions [ service_key ] <EOL> else : return session_key <EOL> service = self . _controller . GetServicesManager ( ) . GetService ( service_key ) <EOL> ( response_gumpf , cookies ) = service . Request ( HC . GET , '<STR_LIT>' , return_cookies = True ) <EOL> try : session_key = cookies [ '<STR_LIT>' ] . decode ( '<STR_LIT>' ) <EOL> except : raise Exception ( '<STR_LIT>' ) <EOL> expires = now + HydrusSessions . HYDRUS_SESSION_LIFETIME <EOL> self . _service_keys_to_sessions [ service_key ] = ( session_key , expires ) <EOL> self . _controller . Write ( '<STR_LIT>' , service_key , session_key , expires ) <EOL> return session_key <EOL> class MenuEventIdToActionCache ( object ) : <EOL> def __init__ ( self ) : <EOL> self . _ids_to_actions = { } <EOL> self . _actions_to_ids = { } <EOL> self . _temporary_ids = set ( ) <EOL> self . _free_temporary_ids = set ( ) <EOL> def _ClearTemporaries ( self ) : <EOL> for temporary_id in self . _temporary_ids . difference ( self . _free_temporary_ids ) : <EOL> temporary_action = self . _ids_to_actions [ temporary_id ] <EOL> del self . _ids_to_actions [ temporary_id ] <EOL> del self . _actions_to_ids [ temporary_action ] <EOL> self . _free_temporary_ids = set ( self . _temporary_ids ) <EOL> def _GetNewId ( self , temporary ) : <EOL> if temporary : <EOL> if len ( self . _free_temporary_ids ) == <NUM_LIT:0> : <EOL> new_id = wx . NewId ( ) <EOL> self . _temporary_ids . add ( new_id ) <EOL> self . _free_temporary_ids . add ( new_id ) <EOL> return self . _free_temporary_ids . pop ( ) <EOL> else : <EOL> return wx . NewId ( ) <EOL> def GetAction ( self , event_id ) : <EOL> action = None <EOL> if event_id in self . _ids_to_actions : <EOL> action = self . _ids_to_actions [ event_id ] <EOL> if event_id in self . _temporary_ids : <EOL> self . _ClearTemporaries ( ) <EOL> return action <EOL> def GetId ( self , command , data = None , temporary = False ) : <EOL> action = ( command , data ) <EOL> if action not in self . _actions_to_ids : <EOL> event_id = self . _GetNewId ( temporary ) <EOL> self . _ids_to_actions [ event_id ] = action <EOL> self . _actions_to_ids [ action ] = event_id <EOL> return self . _actions_to_ids [ action ] <EOL> def GetPermanentId ( self , command , data = None ) : <EOL> return self . GetId ( command , data , False ) <EOL> def GetTemporaryId ( self , command , data = None ) : <EOL> temporary = True <EOL> if data is None : <EOL> temporary = False <EOL> return self . GetId ( command , data , temporary ) <EOL> MENU_EVENT_ID_TO_ACTION_CACHE = MenuEventIdToActionCache ( ) <EOL> class RenderedImageCache ( object ) : <EOL> def __init__ ( self , controller , cache_type ) : <EOL> self . _controller = controller <EOL> self . _type = cache_type <EOL> if self . _type == '<STR_LIT>' : self . _data_cache = DataCache ( self . _controller , '<STR_LIT>' ) <EOL> elif self . _type == '<STR_LIT>' : self . _data_cache = DataCache ( self . _controller , '<STR_LIT>' ) <EOL> def Clear ( self ) : self . _data_cache . Clear ( ) <EOL> def GetImage ( self , media , target_resolution = None ) : <EOL> hash = media . GetHash ( ) <EOL> if target_resolution is None : <EOL> target_resolution = media . GetResolution ( ) <EOL> ( media_width , media_height ) = media . GetResolution ( ) <EOL> ( target_width , target_height ) = target_resolution <EOL> if target_width > media_width or target_height > media_height : <EOL> target_resolution = media . GetResolution ( ) <EOL> else : <EOL> target_resolution = ( target_width , target_height ) <EOL> key = ( hash , target_resolution ) <EOL> if self . _data_cache . HasData ( key ) : <EOL> return self . _data_cache . GetData ( key ) <EOL> else : <EOL> image_container = ClientRendering . RasterContainerImage ( media , target_resolution ) <EOL> self . _data_cache . AddData ( key , image_container ) <EOL> return image_container <EOL> def HasImage ( self , hash , target_resolution ) : <EOL> key = ( hash , target_resolution ) <EOL> return self . _data_cache . HasData ( key ) <EOL> class ThumbnailCache ( object ) : <EOL> def __init__ ( self , controller ) : <EOL> self . _controller = controller <EOL> self . _data_cache = DataCache ( self . _controller , '<STR_LIT>' ) <EOL> self . _lock = threading . Lock ( ) <EOL> self . _waterfall_queue_quick = set ( ) <EOL> self . _waterfall_queue_random = [ ] <EOL> self . _waterfall_event = threading . Event ( ) <EOL> self . _special_thumbs = { } <EOL> self . Clear ( ) <EOL> threading . Thread ( target = self . DAEMONWaterfall , name = '<STR_LIT>' ) . start ( ) <EOL> self . _controller . sub ( self , '<STR_LIT>' , '<STR_LIT>' ) <EOL> def _GetResizedHydrusBitmapFromHardDrive ( self , display_media , from_error = False ) : <EOL> hash = display_media . GetHash ( ) <EOL> path = None <EOL> locations_manager = display_media . GetLocationsManager ( ) <EOL> if locations_manager . HasLocal ( ) : <EOL> try : <EOL> path = ClientFiles . GetThumbnailPath ( hash , False ) <EOL> except HydrusExceptions . FileMissingException as e : <EOL> HydrusData . ShowException ( e ) <EOL> else : <EOL> try : <EOL> path = ClientFiles . GetThumbnailPath ( hash , False ) <EOL> except : <EOL> pass <EOL> if path is None : <EOL> hydrus_bitmap = self . _special_thumbs [ '<STR_LIT>' ] <EOL> else : <EOL> try : <EOL> hydrus_bitmap = ClientRendering . GenerateHydrusBitmap ( path ) <EOL> options = HydrusGlobals . client_controller . GetOptions ( ) <EOL> ( media_x , media_y ) = display_media . GetResolution ( ) <EOL> ( actual_x , actual_y ) = hydrus_bitmap . GetSize ( ) <EOL> ( desired_x , desired_y ) = options [ '<STR_LIT>' ] <EOL> too_large = actual_x > desired_x or actual_y > desired_y <EOL> small_original_image = actual_x == media_x and actual_y == media_y <EOL> too_small = actual_x < desired_x and actual_y < desired_y <EOL> if too_large or ( too_small and not small_original_image ) : <EOL> if not from_error : <EOL> del hydrus_bitmap <EOL> try : <EOL> os . remove ( path ) <EOL> finally : <EOL> hydrus_bitmap = self . _GetResizedHydrusBitmapFromHardDrive ( display_media , from_error = True ) <EOL> except Exception as e : <EOL> if from_error : <EOL> raise <EOL> HydrusData . ShowException ( e ) <EOL> try : <EOL> try : <EOL> os . remove ( path ) <EOL> except Exception as e : <EOL> HydrusData . ShowException ( e ) <EOL> raise HydrusExceptions . FileMissingException ( '<STR_LIT>' + hash . encode ( '<STR_LIT>' ) + '<STR_LIT>' ) <EOL> try : <EOL> hydrus_bitmap = self . _GetResizedHydrusBitmapFromHardDrive ( display_media , from_error = True ) <EOL> except Exception as e : <EOL> HydrusData . ShowException ( e ) <EOL> raise HydrusExceptions . FileMissingException ( '<STR_LIT>' + hash . encode ( '<STR_LIT>' ) + '<STR_LIT>' ) <EOL> HydrusData . ShowText ( '<STR_LIT>' + hash . encode ( '<STR_LIT>' ) + '<STR_LIT>' ) <EOL> except Exception as e : <EOL> HydrusData . ShowException ( e ) <EOL> hydrus_bitmap = self . _special_thumbs [ '<STR_LIT>' ] <EOL> return hydrus_bitmap <EOL> def _RecalcWaterfallQueueRandom ( self ) : <EOL> self . _waterfall_queue_random = list ( self . _waterfall_queue_quick ) <EOL> random . shuffle ( self . _waterfall_queue_random ) <EOL> def CancelWaterfall ( self , page_key , medias ) : <EOL> with self . _lock : <EOL> self . _waterfall_queue_quick . difference_update ( ( ( page_key , media ) for media in medias ) ) <EOL> self . _RecalcWaterfallQueueRandom ( ) <EOL> def Clear ( self ) : <EOL> with self . _lock : <EOL> self . _data_cache . Clear ( ) <EOL> self . _special_thumbs = { } <EOL> names = [ '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ] <EOL> ( os_file_handle , temp_path ) = HydrusPaths . GetTempPath ( ) <EOL> try : <EOL> for name in names : <EOL> path = os . path . join ( HC . STATIC_DIR , name + '<STR_LIT>' ) <EOL> options = self . _controller . GetOptions ( ) <EOL> thumbnail = HydrusFileHandling . GenerateThumbnail ( path , options [ '<STR_LIT>' ] ) <EOL> with open ( temp_path , '<STR_LIT:wb>' ) as f : f . write ( thumbnail ) <EOL> hydrus_bitmap = ClientRendering . GenerateHydrusBitmap ( temp_path ) <EOL> self . _special_thumbs [ name ] = hydrus_bitmap <EOL> finally : <EOL> HydrusPaths . CleanUpTempPath ( os_file_handle , temp_path ) <EOL> def GetThumbnail ( self , media ) : <EOL> display_media = media . GetDisplayMedia ( ) <EOL> if display_media . GetLocationsManager ( ) . ShouldHaveThumbnail ( ) : <EOL> mime = display_media . GetMime ( ) <EOL> if mime in HC . MIMES_WITH_THUMBNAILS : <EOL> hash = display_media . GetHash ( ) <EOL> if not self . _data_cache . HasData ( hash ) : <EOL> hydrus_bitmap = self . _GetResizedHydrusBitmapFromHardDrive ( display_media ) <EOL> self . _data_cache . AddData ( hash , hydrus_bitmap ) <EOL> return self . _data_cache . GetData ( hash ) <EOL> elif mime in HC . AUDIO : return self . _special_thumbs [ '<STR_LIT>' ] <EOL> elif mime in HC . VIDEO : return self . _special_thumbs [ '<STR_LIT>' ] <EOL> elif mime == HC . APPLICATION_FLASH : return self . _special_thumbs [ '<STR_LIT>' ] <EOL> elif mime == HC . APPLICATION_PDF : return self . _special_thumbs [ '<STR_LIT>' ] <EOL> else : return self . _special_thumbs [ '<STR_LIT>' ] <EOL> else : <EOL> return self . _special_thumbs [ '<STR_LIT>' ] <EOL> def HasThumbnailCached ( self , media ) : <EOL> display_media = media . GetDisplayMedia ( ) <EOL> mime = display_media . GetMime ( ) <EOL> if mime in HC . MIMES_WITH_THUMBNAILS : <EOL> hash = display_media . GetHash ( ) <EOL> return self . _data_cache . HasData ( hash ) <EOL> else : <EOL> return True <EOL> def Waterfall ( self , page_key , medias ) : <EOL> with self . _lock : <EOL> self . _waterfall_queue_quick . update ( ( ( page_key , media ) for media in medias ) ) <EOL> self . _RecalcWaterfallQueueRandom ( ) <EOL> self . _waterfall_event . set ( ) <EOL> def DAEMONWaterfall ( self ) : <EOL> last_paused = HydrusData . GetNowPrecise ( ) <EOL> while not HydrusGlobals . view_shutdown : <EOL> with self . _lock : <EOL> do_wait = len ( self . _waterfall_queue_random ) == <NUM_LIT:0> <EOL> if do_wait : <EOL> self . _waterfall_event . wait ( <NUM_LIT:1> ) <EOL> self . _waterfall_event . clear ( ) <EOL> last_paused = HydrusData . GetNowPrecise ( ) <EOL> with self . _lock : <EOL> if len ( self . _waterfall_queue_random ) == <NUM_LIT:0> : <EOL> continue <EOL> else : <EOL> result = self . _waterfall_queue_random . pop ( <NUM_LIT:0> ) <EOL> self . _waterfall_queue_quick . discard ( result ) <EOL> ( page_key , media ) = result <EOL> try : <EOL> self . GetThumbnail ( media ) <EOL> self . _controller . pub ( '<STR_LIT>' , page_key , media ) <EOL> if HydrusData . GetNowPrecise ( ) - last_paused > <NUM_LIT> : <EOL> time . sleep ( <NUM_LIT> ) <EOL> last_paused = HydrusData . GetNowPrecise ( ) <EOL> except Exception as e : <EOL> HydrusData . ShowException ( e ) <EOL> class ServicesManager ( object ) : <EOL> def __init__ ( self , controller ) : <EOL> self . _controller = controller <EOL> self . _lock = threading . Lock ( ) <EOL> self . _keys_to_services = { } <EOL> self . _services_sorted = [ ] <EOL> self . RefreshServices ( ) <EOL> self . _controller . sub ( self , '<STR_LIT>' , '<STR_LIT>' ) <EOL> def FilterValidServiceKeys ( self , service_keys ) : <EOL> with self . _lock : <EOL> filtered_service_keys = [ service_key for service_key in service_keys if service_key in self . _keys_to_services ] <EOL> return filtered_service_keys <EOL> def GetService ( self , service_key ) : <EOL> with self . _lock : <EOL> try : <EOL> return self . _keys_to_services [ service_key ] <EOL> except KeyError : <EOL> raise HydrusExceptions . DataMissing ( '<STR_LIT>' ) <EOL> def GetServices ( self , types = HC . ALL_SERVICES , randomised = True ) : <EOL> with self . _lock : <EOL> services = [ service for service in self . _services_sorted if service . GetServiceType ( ) in types ] <EOL> if randomised : <EOL> random . shuffle ( services ) <EOL> return services <EOL> def RefreshServices ( self ) : <EOL> with self . _lock : <EOL> services = self . _controller . Read ( '<STR_LIT>' ) <EOL> self . _keys_to_services = { service . GetServiceKey ( ) : service for service in services } <EOL> compare_function = lambda a , b : cmp ( a . GetName ( ) , b . GetName ( ) ) <EOL> self . _services_sorted = list ( services ) <EOL> self . _services_sorted . sort ( cmp = compare_function ) <EOL> class TagCensorshipManager ( object ) : <EOL> def __init__ ( self , controller ) : <EOL> self . _controller = controller <EOL> self . RefreshData ( ) <EOL> self . _controller . sub ( self , '<STR_LIT>' , '<STR_LIT>' ) <EOL> def _CensorshipMatches ( self , tag , blacklist , censorships ) : <EOL> if blacklist : <EOL> return not HydrusTags . CensorshipMatch ( tag , censorships ) <EOL> else : <EOL> return HydrusTags . CensorshipMatch ( tag , censorships ) <EOL> def GetInfo ( self , service_key ) : <EOL> if service_key in self . _service_keys_to_info : return self . _service_keys_to_info [ service_key ] <EOL> else : return ( True , set ( ) ) <EOL> def RefreshData ( self ) : <EOL> rows = self . _controller . Read ( '<STR_LIT>' ) <EOL> self . _service_keys_to_info = { service_key : ( blacklist , censorships ) for ( service_key , blacklist , censorships ) in rows } <EOL> def FilterStatusesToPairs ( self , service_key , statuses_to_pairs ) : <EOL> for service_key_lookup in ( CC . COMBINED_TAG_SERVICE_KEY , service_key ) : <EOL> if service_key_lookup in self . _service_keys_to_info : <EOL> ( blacklist , censorships ) = self . _service_keys_to_info [ service_key_lookup ] <EOL> new_statuses_to_pairs = HydrusData . default_dict_set ( ) <EOL> for ( status , pairs ) in statuses_to_pairs . items ( ) : <EOL> new_statuses_to_pairs [ status ] = { ( one , two ) for ( one , two ) in pairs if self . _CensorshipMatches ( one , blacklist , censorships ) and self . _CensorshipMatches ( two , blacklist , censorships ) } <EOL> statuses_to_pairs = new_statuses_to_pairs <EOL> return statuses_to_pairs <EOL> def FilterServiceKeysToStatusesToTags ( self , service_keys_to_statuses_to_tags ) : <EOL> if CC . COMBINED_TAG_SERVICE_KEY in self . _service_keys_to_info : <EOL> ( blacklist , censorships ) = self . _service_keys_to_info [ CC . COMBINED_TAG_SERVICE_KEY ] <EOL> service_keys = service_keys_to_statuses_to_tags . keys ( ) <EOL> for service_key in service_keys : <EOL> statuses_to_tags = service_keys_to_statuses_to_tags [ service_key ] <EOL> statuses = statuses_to_tags . keys ( ) <EOL> for status in statuses : <EOL> tags = statuses_to_tags [ status ] <EOL> statuses_to_tags [ status ] = { tag for tag in tags if self . _CensorshipMatches ( tag , blacklist , censorships ) } <EOL> for ( service_key , ( blacklist , censorships ) ) in self . _service_keys_to_info . items ( ) : <EOL> if service_key == CC . COMBINED_TAG_SERVICE_KEY : <EOL> continue <EOL> if service_key in service_keys_to_statuses_to_tags : <EOL> statuses_to_tags = service_keys_to_statuses_to_tags [ service_key ] <EOL> statuses = statuses_to_tags . keys ( ) <EOL> for status in statuses : <EOL> tags = statuses_to_tags [ status ] <EOL> statuses_to_tags [ status ] = { tag for tag in tags if self . _CensorshipMatches ( tag , blacklist , censorships ) } <EOL> return service_keys_to_statuses_to_tags <EOL> def FilterTags ( self , service_key , tags ) : <EOL> for service_key_lookup in ( CC . COMBINED_TAG_SERVICE_KEY , service_key ) : <EOL> if service_key_lookup in self . _service_keys_to_info : <EOL> ( blacklist , censorships ) = self . _service_keys_to_info [ service_key_lookup ] <EOL> tags = { tag for tag in tags if self . _CensorshipMatches ( tag , blacklist , censorships ) } <EOL> return tags <EOL> class TagParentsManager ( object ) : <EOL> def __init__ ( self , controller ) : <EOL> self . _controller = controller <EOL> self . _service_keys_to_children_to_parents = collections . defaultdict ( HydrusData . default_dict_list ) <EOL> self . _RefreshParents ( ) <EOL> self . _lock = threading . Lock ( ) <EOL> self . _controller . sub ( self , '<STR_LIT>' , '<STR_LIT>' ) <EOL> def _RefreshParents ( self ) : <EOL> service_keys_to_statuses_to_pairs = self . _controller . Read ( '<STR_LIT>' ) <EOL> sibling_manager = self . _controller . GetManager ( '<STR_LIT>' ) <EOL> collapsed_service_keys_to_statuses_to_pairs = collections . defaultdict ( HydrusData . default_dict_set ) <EOL> for ( service_key , statuses_to_pairs ) in service_keys_to_statuses_to_pairs . items ( ) : <EOL> if service_key == CC . COMBINED_TAG_SERVICE_KEY : continue <EOL> for ( status , pairs ) in statuses_to_pairs . items ( ) : <EOL> pairs = sibling_manager . CollapsePairs ( pairs ) <EOL> collapsed_service_keys_to_statuses_to_pairs [ service_key ] [ status ] = pairs <EOL> service_keys_to_pairs_flat = HydrusData . default_dict_set ( ) <EOL> for ( service_key , statuses_to_pairs ) in collapsed_service_keys_to_statuses_to_pairs . items ( ) : <EOL> pairs_flat = statuses_to_pairs [ HC . CURRENT ] . union ( statuses_to_pairs [ HC . PENDING ] ) <EOL> service_keys_to_pairs_flat [ service_key ] = pairs_flat <EOL> combined_pairs_flat = set ( ) <EOL> for pairs_flat in service_keys_to_pairs_flat . values ( ) : <EOL> combined_pairs_flat . update ( pairs_flat ) <EOL> service_keys_to_pairs_flat [ CC . COMBINED_TAG_SERVICE_KEY ] = combined_pairs_flat <EOL> service_keys_to_simple_children_to_parents = BuildServiceKeysToSimpleChildrenToParents ( service_keys_to_pairs_flat ) <EOL> self . _service_keys_to_children_to_parents = BuildServiceKeysToChildrenToParents ( service_keys_to_simple_children_to_parents ) <EOL> def ExpandPredicates ( self , service_key , predicates ) : <EOL> new_options = self . _controller . GetNewOptions ( ) <EOL> if new_options . GetBoolean ( '<STR_LIT>' ) : <EOL> service_key = CC . COMBINED_TAG_SERVICE_KEY <EOL> results = [ ] <EOL> with self . _lock : <EOL> for predicate in predicates : <EOL> results . append ( predicate ) <EOL> if predicate . GetType ( ) == HC . PREDICATE_TYPE_TAG : <EOL> tag = predicate . GetValue ( ) <EOL> parents = self . _service_keys_to_children_to_parents [ service_key ] [ tag ] <EOL> for parent in parents : <EOL> parent_predicate = ClientSearch . Predicate ( HC . PREDICATE_TYPE_PARENT , parent ) <EOL> results . append ( parent_predicate ) <EOL> return results <EOL> def ExpandTags ( self , service_key , tags ) : <EOL> new_options = self . _controller . GetNewOptions ( ) <EOL> if new_options . GetBoolean ( '<STR_LIT>' ) : <EOL> service_key = CC . COMBINED_TAG_SERVICE_KEY <EOL> with self . _lock : <EOL> tags_results = set ( tags ) <EOL> for tag in tags : <EOL> tags_results . update ( self . _service_keys_to_children_to_parents [ service_key ] [ tag ] ) <EOL> return tags_results <EOL> def GetParents ( self , service_key , tag ) : <EOL> new_options = self . _controller . GetNewOptions ( ) <EOL> if new_options . GetBoolean ( '<STR_LIT>' ) : <EOL> service_key = CC . COMBINED_TAG_SERVICE_KEY <EOL> with self . _lock : <EOL> return self . _service_keys_to_children_to_parents [ service_key ] [ tag ] <EOL> def RefreshParents ( self ) : <EOL> with self . _lock : <EOL> self . _RefreshParents ( ) <EOL> class TagSiblingsManager ( object ) : <EOL> def __init__ ( self , controller ) : <EOL> self . _controller = controller <EOL> self . _RefreshSiblings ( ) <EOL> self . _lock = threading . Lock ( ) <EOL> self . _controller . sub ( self , '<STR_LIT>' , '<STR_LIT>' ) <EOL> def _CollapseTags ( self , tags ) : <EOL> return { self . _siblings [ tag ] if tag in self . _siblings else tag for tag in tags } <EOL> def _RefreshSiblings ( self ) : <EOL> service_keys_to_statuses_to_pairs = self . _controller . Read ( '<STR_LIT>' ) <EOL> processed_siblings = CombineTagSiblingPairs ( service_keys_to_statuses_to_pairs ) <EOL> ( self . _siblings , self . _reverse_lookup ) = CollapseTagSiblingChains ( processed_siblings ) <EOL> self . _controller . pub ( '<STR_LIT>' ) <EOL> def GetAutocompleteSiblings ( self , search_text , exact_match = False ) : <EOL> with self . _lock : <EOL> if exact_match : <EOL> key_based_matching_values = set ( ) <EOL> if search_text in self . _siblings : <EOL> key_based_matching_values = { self . _siblings [ search_text ] } <EOL> else : <EOL> key_based_matching_values = set ( ) <EOL> value_based_matching_values = { value for value in self . _siblings . values ( ) if value == search_text } <EOL> else : <EOL> matching_keys = ClientSearch . FilterTagsBySearchEntry ( search_text , self . _siblings . keys ( ) , search_siblings = False ) <EOL> key_based_matching_values = { self . _siblings [ key ] for key in matching_keys } <EOL> value_based_matching_values = ClientSearch . FilterTagsBySearchEntry ( search_text , self . _siblings . values ( ) , search_siblings = False ) <EOL> matching_values = key_based_matching_values . union ( value_based_matching_values ) <EOL> lists_of_matching_keys = [ self . _reverse_lookup [ value ] for value in matching_values ] <EOL> matching_keys = itertools . chain . from_iterable ( lists_of_matching_keys ) <EOL> matches = matching_values . union ( matching_keys ) <EOL> return matches <EOL> def GetSibling ( self , tag ) : <EOL> with self . _lock : <EOL> if tag in self . _siblings : return self . _siblings [ tag ] <EOL> else : return None <EOL> def GetAllSiblings ( self , tag ) : <EOL> with self . _lock : <EOL> if tag in self . _siblings : <EOL> new_tag = self . _siblings [ tag ] <EOL> elif tag in self . _reverse_lookup : new_tag = tag <EOL> else : return [ tag ] <EOL> all_siblings = list ( self . _reverse_lookup [ new_tag ] ) <EOL> all_siblings . append ( new_tag ) <EOL> return all_siblings <EOL> def RefreshSiblings ( self ) : <EOL> with self . _lock : self . _RefreshSiblings ( ) <EOL> def CollapseNamespacedTags ( self , namespace , tags ) : <EOL> with self . _lock : <EOL> results = set ( ) <EOL> for tag in tags : <EOL> full_tag = namespace + '<STR_LIT::>' + tag <EOL> if full_tag in self . _siblings : <EOL> sibling = self . _siblings [ full_tag ] <EOL> if '<STR_LIT::>' in sibling : sibling = sibling . split ( '<STR_LIT::>' , <NUM_LIT:1> ) [ <NUM_LIT:1> ] <EOL> results . add ( sibling ) <EOL> else : results . add ( tag ) <EOL> return results <EOL> def CollapsePredicates ( self , predicates ) : <EOL> with self . _lock : <EOL> results = [ predicate for predicate in predicates if predicate . GetType ( ) != HC . PREDICATE_TYPE_TAG ] <EOL> tag_predicates = [ predicate for predicate in predicates if predicate . GetType ( ) == HC . PREDICATE_TYPE_TAG ] <EOL> tags_to_predicates = { predicate . GetValue ( ) : predicate for predicate in predicates if predicate . GetType ( ) == HC . PREDICATE_TYPE_TAG } <EOL> tags = tags_to_predicates . keys ( ) <EOL> tags_to_include_in_results = set ( ) <EOL> for tag in tags : <EOL> if tag in self . _siblings : <EOL> old_tag = tag <EOL> old_predicate = tags_to_predicates [ old_tag ] <EOL> new_tag = self . _siblings [ old_tag ] <EOL> if new_tag not in tags_to_predicates : <EOL> ( old_pred_type , old_value , old_inclusive ) = old_predicate . GetInfo ( ) <EOL> new_predicate = ClientSearch . Predicate ( old_pred_type , new_tag , inclusive = old_inclusive ) <EOL> tags_to_predicates [ new_tag ] = new_predicate <EOL> tags_to_include_in_results . add ( new_tag ) <EOL> new_predicate = tags_to_predicates [ new_tag ] <EOL> current_count = old_predicate . GetCount ( HC . CURRENT ) <EOL> pending_count = old_predicate . GetCount ( HC . PENDING ) <EOL> new_predicate . AddToCount ( HC . CURRENT , current_count ) <EOL> new_predicate . AddToCount ( HC . PENDING , pending_count ) <EOL> else : <EOL> tags_to_include_in_results . add ( tag ) <EOL> results . extend ( [ tags_to_predicates [ tag ] for tag in tags_to_include_in_results ] ) <EOL> return results <EOL> def CollapsePairs ( self , pairs ) : <EOL> with self . _lock : <EOL> result = set ( ) <EOL> for ( a , b ) in pairs : <EOL> if a in self . _siblings : a = self . _siblings [ a ] <EOL> if b in self . _siblings : b = self . _siblings [ b ] <EOL> result . add ( ( a , b ) ) <EOL> return result <EOL> def CollapseStatusesToTags ( self , statuses_to_tags ) : <EOL> with self . _lock : <EOL> statuses = statuses_to_tags . keys ( ) <EOL> for status in statuses : <EOL> statuses_to_tags [ status ] = self . _CollapseTags ( statuses_to_tags [ status ] ) <EOL> return statuses_to_tags <EOL> def CollapseTags ( self , tags ) : <EOL> with self . _lock : <EOL> return self . _CollapseTags ( tags ) <EOL> def CollapseTagsToCount ( self , tags_to_count ) : <EOL> with self . _lock : <EOL> results = collections . Counter ( ) <EOL> for ( tag , count ) in tags_to_count . items ( ) : <EOL> if tag in self . _siblings : tag = self . _siblings [ tag ] <EOL> results [ tag ] += count <EOL> return results <EOL> class UndoManager ( object ) : <EOL> def __init__ ( self , controller ) : <EOL> self . _controller = controller <EOL> self . _commands = [ ] <EOL> self . _inverted_commands = [ ] <EOL> self . _current_index = <NUM_LIT:0> <EOL> self . _lock = threading . Lock ( ) <EOL> self . _controller . sub ( self , '<STR_LIT>' , '<STR_LIT>' ) <EOL> self . _controller . sub ( self , '<STR_LIT>' , '<STR_LIT>' ) <EOL> def _FilterServiceKeysToContentUpdates ( self , service_keys_to_content_updates ) : <EOL> filtered_service_keys_to_content_updates = { } <EOL> for ( service_key , content_updates ) in service_keys_to_content_updates . items ( ) : <EOL> filtered_content_updates = [ ] <EOL> for content_update in content_updates : <EOL> ( data_type , action , row ) = content_update . ToTuple ( ) <EOL> if data_type == HC . CONTENT_TYPE_FILES : <EOL> if action in ( HC . CONTENT_UPDATE_ADD , HC . CONTENT_UPDATE_DELETE , HC . CONTENT_UPDATE_UNDELETE , HC . CONTENT_UPDATE_RESCIND_PETITION , HC . CONTENT_UPDATE_ADVANCED ) : continue <EOL> elif data_type == HC . CONTENT_TYPE_MAPPINGS : <EOL> if action in ( HC . CONTENT_UPDATE_RESCIND_PETITION , HC . CONTENT_UPDATE_ADVANCED ) : continue <EOL> else : continue <EOL> filtered_content_update = HydrusData . ContentUpdate ( data_type , action , row ) <EOL> filtered_content_updates . append ( filtered_content_update ) <EOL> if len ( filtered_content_updates ) > <NUM_LIT:0> : <EOL> filtered_service_keys_to_content_updates [ service_key ] = filtered_content_updates <EOL> return filtered_service_keys_to_content_updates <EOL> def _InvertServiceKeysToContentUpdates ( self , service_keys_to_content_updates ) : <EOL> inverted_service_keys_to_content_updates = { } <EOL> for ( service_key , content_updates ) in service_keys_to_content_updates . items ( ) : <EOL> inverted_content_updates = [ ] <EOL> for content_update in content_updates : <EOL> ( data_type , action , row ) = content_update . ToTuple ( ) <EOL> inverted_row = row <EOL> if data_type == HC . CONTENT_TYPE_FILES : <EOL> if action == HC . CONTENT_UPDATE_ARCHIVE : inverted_action = HC . CONTENT_UPDATE_INBOX <EOL> elif action == HC . CONTENT_UPDATE_INBOX : inverted_action = HC . CONTENT_UPDATE_ARCHIVE <EOL> elif action == HC . CONTENT_UPDATE_PEND : inverted_action = HC . CONTENT_UPDATE_RESCIND_PEND <EOL> elif action == HC . CONTENT_UPDATE_RESCIND_PEND : inverted_action = HC . CONTENT_UPDATE_PEND <EOL> elif action == HC . CONTENT_UPDATE_PETITION : <EOL> inverted_action = HC . CONTENT_UPDATE_RESCIND_PETITION <EOL> ( hashes , reason ) = row <EOL> inverted_row = hashes <EOL> elif data_type == HC . CONTENT_TYPE_MAPPINGS : <EOL> if action == HC . CONTENT_UPDATE_ADD : inverted_action = HC . CONTENT_UPDATE_DELETE <EOL> elif action == HC . CONTENT_UPDATE_DELETE : inverted_action = HC . CONTENT_UPDATE_ADD <EOL> elif action == HC . CONTENT_UPDATE_PEND : inverted_action = HC . CONTENT_UPDATE_RESCIND_PEND <EOL> elif action == HC . CONTENT_UPDATE_RESCIND_PEND : inverted_action = HC . CONTENT_UPDATE_PEND <EOL> elif action == HC . CONTENT_UPDATE_PETITION : <EOL> inverted_action = HC . CONTENT_UPDATE_RESCIND_PETITION <EOL> ( tag , hashes , reason ) = row <EOL> inverted_row = ( tag , hashes ) <EOL> inverted_content_update = HydrusData . ContentUpdate ( data_type , inverted_action , inverted_row ) <EOL> inverted_content_updates . append ( inverted_content_update ) <EOL> inverted_service_keys_to_content_updates [ service_key ] = inverted_content_updates <EOL> return inverted_service_keys_to_content_updates <EOL> def AddCommand ( self , action , * args , ** kwargs ) : <EOL> with self . _lock : <EOL> inverted_action = action <EOL> inverted_args = args <EOL> inverted_kwargs = kwargs <EOL> if action == '<STR_LIT>' : <EOL> ( service_keys_to_content_updates , ) = args <EOL> service_keys_to_content_updates = self . _FilterServiceKeysToContentUpdates ( service_keys_to_content_updates ) <EOL> if len ( service_keys_to_content_updates ) == <NUM_LIT:0> : return <EOL> inverted_service_keys_to_content_updates = self . _InvertServiceKeysToContentUpdates ( service_keys_to_content_updates ) <EOL> if len ( inverted_service_keys_to_content_updates ) == <NUM_LIT:0> : return <EOL> inverted_args = ( inverted_service_keys_to_content_updates , ) <EOL> else : return <EOL> self . _commands = self . _commands [ : self . _current_index ] <EOL> self . _inverted_commands = self . _inverted_commands [ : self . _current_index ] <EOL> self . _commands . append ( ( action , args , kwargs ) ) <EOL> self . _inverted_commands . append ( ( inverted_action , inverted_args , inverted_kwargs ) ) <EOL> self . _current_index += <NUM_LIT:1> <EOL> self . _controller . pub ( '<STR_LIT>' ) <EOL> def GetUndoRedoStrings ( self ) : <EOL> with self . _lock : <EOL> ( undo_string , redo_string ) = ( None , None ) <EOL> if self . _current_index > <NUM_LIT:0> : <EOL> undo_index = self . _current_index - <NUM_LIT:1> <EOL> ( action , args , kwargs ) = self . _commands [ undo_index ] <EOL> if action == '<STR_LIT>' : <EOL> ( service_keys_to_content_updates , ) = args <EOL> undo_string = '<STR_LIT>' + ClientData . ConvertServiceKeysToContentUpdatesToPrettyString ( service_keys_to_content_updates ) <EOL> if len ( self . _commands ) > <NUM_LIT:0> and self . _current_index < len ( self . _commands ) : <EOL> redo_index = self . _current_index <EOL> ( action , args , kwargs ) = self . _commands [ redo_index ] <EOL> if action == '<STR_LIT>' : <EOL> ( service_keys_to_content_updates , ) = args <EOL> redo_string = '<STR_LIT>' + ClientData . ConvertServiceKeysToContentUpdatesToPrettyString ( service_keys_to_content_updates ) <EOL> return ( undo_string , redo_string ) <EOL> def Undo ( self ) : <EOL> action = None <EOL> with self . _lock : <EOL> if self . _current_index > <NUM_LIT:0> : <EOL> self . _current_index -= <NUM_LIT:1> <EOL> ( action , args , kwargs ) = self . _inverted_commands [ self . _current_index ] <EOL> if action is not None : <EOL> self . _controller . WriteSynchronous ( action , * args , ** kwargs ) <EOL> self . _controller . pub ( '<STR_LIT>' ) <EOL> def Redo ( self ) : <EOL> action = None <EOL> with self . _lock : <EOL> if len ( self . _commands ) > <NUM_LIT:0> and self . _current_index < len ( self . _commands ) : <EOL> ( action , args , kwargs ) = self . _commands [ self . _current_index ] <EOL> self . _current_index += <NUM_LIT:1> <EOL> if action is not None : <EOL> self . _controller . WriteSynchronous ( action , * args , ** kwargs ) <EOL> self . _controller . pub ( '<STR_LIT>' ) <EOL> class WebSessionManagerClient ( object ) : <EOL> def __init__ ( self , controller ) : <EOL> self . _controller = controller <EOL> existing_sessions = self . _controller . Read ( '<STR_LIT>' ) <EOL> self . _names_to_sessions = { name : ( cookies , expires ) for ( name , cookies , expires ) in existing_sessions } <EOL> self . _lock = threading . Lock ( ) <EOL> def GetCookies ( self , name ) : <EOL> now = HydrusData . GetNow ( ) <EOL> with self . _lock : <EOL> if name in self . _names_to_sessions : <EOL> ( cookies , expires ) = self . _names_to_sessions [ name ] <EOL> if HydrusData . TimeHasPassed ( expires - <NUM_LIT> ) : del self . _names_to_sessions [ name ] <EOL> else : return cookies <EOL> if name == '<STR_LIT>' : <EOL> ( response_gumpf , cookies ) = self . _controller . DoHTTP ( HC . GET , '<STR_LIT>' , return_cookies = True ) <EOL> expires = now + <NUM_LIT:30> * <NUM_LIT> <EOL> if name == '<STR_LIT>' : <EOL> ( response_gumpf , cookies ) = self . _controller . DoHTTP ( HC . GET , '<STR_LIT>' , return_cookies = True ) <EOL> raw_csrf = cookies [ '<STR_LIT>' ] <EOL> processed_csrf = urllib . unquote ( raw_csrf ) <EOL> csrf_token = processed_csrf . split ( '<STR_LIT:">' ) [ <NUM_LIT:1> ] <EOL> hentai_foundry_form_info = ClientDefaults . GetDefaultHentaiFoundryInfo ( ) <EOL> hentai_foundry_form_info [ '<STR_LIT>' ] = csrf_token <EOL> body = urllib . urlencode ( hentai_foundry_form_info ) <EOL> request_headers = { } <EOL> ClientNetworking . AddCookiesToHeaders ( cookies , request_headers ) <EOL> request_headers [ '<STR_LIT:Content-Type>' ] = '<STR_LIT>' <EOL> self . _controller . DoHTTP ( HC . POST , '<STR_LIT>' , request_headers = request_headers , body = body ) <EOL> expires = now + <NUM_LIT> * <NUM_LIT> <EOL> elif name == '<STR_LIT>' : <EOL> result = self . _controller . Read ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> if result is None : <EOL> raise HydrusExceptions . DataMissing ( '<STR_LIT>' ) <EOL> ( id , password ) = result <EOL> form_fields = { } <EOL> form_fields [ '<STR_LIT>' ] = '<STR_LIT>' <EOL> form_fields [ '<STR_LIT>' ] = id <EOL> form_fields [ '<STR_LIT>' ] = password <EOL> form_fields [ '<STR_LIT>' ] = '<STR_LIT:1>' <EOL> body = urllib . urlencode ( form_fields ) <EOL> headers = { } <EOL> headers [ '<STR_LIT:Content-Type>' ] = '<STR_LIT>' <EOL> ( response_gumpf , cookies ) = self . _controller . DoHTTP ( HC . POST , '<STR_LIT>' , request_headers = headers , body = body , return_cookies = True ) <EOL> if '<STR_LIT>' not in cookies or '<STR_LIT:_>' not in cookies [ '<STR_LIT>' ] : raise Exception ( '<STR_LIT>' ) <EOL> expires = now + <NUM_LIT:30> * <NUM_LIT> <EOL> self . _names_to_sessions [ name ] = ( cookies , expires ) <EOL> self . _controller . Write ( '<STR_LIT>' , name , cookies , expires ) <EOL> return cookies </s>
