Version 183
This commit is contained in:
parent
facd3ded44
commit
8a84453f89
|
@ -1,19 +0,0 @@
|
|||
upnpc : miniupnpc library test client. (c) 2005-2013 Thomas Bernard
|
||||
Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
for more information.
|
||||
List of UPNP devices found on the network :
|
||||
desc: http://192.168.0.1/root.sxml
|
||||
st: urn:schemas-upnp-org:device:InternetGatewayDevice:1
|
||||
|
||||
Found valid IGD : http://192.168.0.1:4444/wipconn
|
||||
Local LAN ip address : 192.168.0.195
|
||||
Connection Type : IP_Routed
|
||||
Status : Connected, uptime=83462s, LastConnectionError : ERROR_NONE
|
||||
Time started : Mon Aug 10 14:49:40 2015
|
||||
MaxBitRateDown : 1000000000 bps (1000.0 Mbps) MaxBitRateUp 1000000000 bps (1000.0 Mbps)
|
||||
ExternalIPAddress = 98.213.207.109
|
||||
i protocol exPort->inAddr:inPort description remoteHost leaseTime
|
||||
0 UDP 45871->192.168.0.103:45871 'Public Tags' '' 0
|
||||
1 UDP 45872->192.168.0.103:45872 'File Repo' '' 0
|
||||
2 UDP 45873->192.168.0.103:45873 'Message Depot' '' 0
|
||||
GetGenericPortMappingEntry() returned 713 (SpecifiedArrayIndexInvalid)
|
|
@ -1,3 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
# This program is free software. It comes without any warranty, to
|
||||
# the extent permitted by applicable law. You can redistribute it
|
||||
# and/or modify it under the terms of the Do What The Fuck You Want
|
||||
|
|
|
@ -8,6 +8,40 @@
|
|||
<div class="content">
|
||||
<h3>changelog</h3>
|
||||
<ul>
|
||||
<li><h3>version 183</h3></li>
|
||||
<ul>
|
||||
<li>added swf thumbnail support--it works ok for most swfs!</li>
|
||||
<li>thumbs for existing swf files will generate on db update for both client and server</li>
|
||||
<li>the server will also generate thumbnails for video on update, which it seems it was not doing before</li>
|
||||
<li>rewrote some hash comparisons in thumbnail downloading and thumbnail counting code to be a lot faster and memory efficient</li>
|
||||
<li>fixed thumbnail count invalidation after service sync</li>
|
||||
<li>in certain cases, fetching autocomplete tag results from the db will be slightly less laggy</li>
|
||||
<li>if the autocomplete dropdown has cached or otherwise quickly fetchable results, it will refilter for current input as you type, ignoring the normal character delay (i.e. typing through autocomplete is far less laggy now)</li>
|
||||
<li>fixed a couple of autocomplete tag-parsing bugs for tags with more than one colon character</li>
|
||||
<li>fixed some key event selection bugs in the autocomplete taglist when there are no results in the list</li>
|
||||
<li>if there are no results in the autocomplete taglist, the typically caret-moving key events up/down/home/end will move the caret (rather than being uselessly passed on to the empty taglist)</li>
|
||||
<li>all profiling now goes through a single location</li>
|
||||
<li>profiling now also prints extensive information on explicit code callers</li>
|
||||
<li>fixed db profile mode printing display for the new logger</li>
|
||||
<li>added new pubsub_profile_mode (AKA log-killer)</li>
|
||||
<li>all menu popup display and explicit memory cleanup is done through a single location</li>
|
||||
<li>hover windows will now not show whenever a menu is open</li>
|
||||
<li>hover windows will now not hide whenever a menu is open (useful when trying to go 'copy tag' off the hover taglist's menu!)</li>
|
||||
<li>a keyerror bug when force_idle_mode was hit right at program start is fixed</li>
|
||||
<li>unexpected serverside client disconnections are now caught and further request processing is cancelled</li>
|
||||
<li>middle clicking on an 'empty' system predicate in the a/c dropdown now will throw up the dialog to enter a value and then pass that filled in system pred onto the new search page</li>
|
||||
<li>duplicate parents (which can occur with overlapping grandparents) are now collapsed</li>
|
||||
<li>the upload pending popup message cancels properly after 'server busy' events</li>
|
||||
<li>whenever the client's services are iterated at the view-level, it will now be in random order, to stop sync bottlenecks choking other services (and anything else like this that might have been occuring)</li>
|
||||
<li>fixed a bug with double-clicking a tag selection on the the tag censorship taglist</li>
|
||||
<li>fixed the too-fast frame timings on some videos opencv had a problem parsing</li>
|
||||
<li>loading many video types will now be just a little faster</li>
|
||||
<li>remote files will no longer present the right-click menu option to share->copy->file</li>
|
||||
<li>hitting a shortcut for manage ratings from the media viewer canvas will no longer work if you have no ratings services</li>
|
||||
<li>the base scripts (client.pyw, server.py and test.py) now have a shebang line to facilitate non-Windows use</li>
|
||||
<li>laid groundwork for external client_files locations</li>
|
||||
<li>plenty of misc cleaning and refactoring</li>
|
||||
</ul>
|
||||
<li><h3>version 182</h3></li>
|
||||
<ul>
|
||||
<li>all printing to the log should now be unicode safe</li>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -44,6 +44,7 @@ class Controller( HydrusController.HydrusController ):
|
|||
HydrusGlobals.client_controller = self
|
||||
|
||||
self._last_mouse_position = None
|
||||
self._menu_open = False
|
||||
|
||||
|
||||
def _InitDB( self ):
|
||||
|
@ -361,8 +362,15 @@ class Controller( HydrusController.HydrusController ):
|
|||
|
||||
def ForceIdle( self ):
|
||||
|
||||
del self._timestamps[ 'last_user_action' ]
|
||||
del self._timestamps[ 'last_mouse_action' ]
|
||||
if 'last_user_action' in self._timestamps:
|
||||
|
||||
del self._timestamps[ 'last_user_action' ]
|
||||
|
||||
|
||||
if 'last_mouse_action' in self._timestamps:
|
||||
|
||||
del self._timestamps[ 'last_mouse_action' ]
|
||||
|
||||
|
||||
self._last_mouse_position = None
|
||||
|
||||
|
@ -410,15 +418,15 @@ class Controller( HydrusController.HydrusController ):
|
|||
|
||||
HC.options = self._options
|
||||
|
||||
self._services_manager = ClientData.ServicesManager()
|
||||
self._services_manager = ClientCaches.ServicesManager( self )
|
||||
|
||||
self._managers[ 'hydrus_sessions' ] = ClientCaches.HydrusSessionManagerClient()
|
||||
self._managers[ 'local_booru' ] = ClientCaches.LocalBooruCache()
|
||||
self._managers[ 'tag_censorship' ] = ClientCaches.TagCensorshipManager()
|
||||
self._managers[ 'tag_siblings' ] = ClientCaches.TagSiblingsManager()
|
||||
self._managers[ 'tag_parents' ] = ClientCaches.TagParentsManager()
|
||||
self._managers[ 'undo' ] = ClientData.UndoManager()
|
||||
self._managers[ 'web_sessions' ] = ClientCaches.WebSessionManagerClient()
|
||||
self._managers[ 'hydrus_sessions' ] = ClientCaches.HydrusSessionManager( self )
|
||||
self._managers[ 'local_booru' ] = ClientCaches.LocalBooruCache( self )
|
||||
self._managers[ 'tag_censorship' ] = ClientCaches.TagCensorshipManager( self )
|
||||
self._managers[ 'tag_siblings' ] = ClientCaches.TagSiblingsManager( self )
|
||||
self._managers[ 'tag_parents' ] = ClientCaches.TagParentsManager( self )
|
||||
self._managers[ 'undo' ] = ClientCaches.UndoManager( self )
|
||||
self._managers[ 'web_sessions' ] = ClientCaches.WebSessionManagerClient( self )
|
||||
|
||||
if HC.options[ 'proxy' ] is not None:
|
||||
|
||||
|
@ -429,9 +437,9 @@ class Controller( HydrusController.HydrusController ):
|
|||
|
||||
def wx_code():
|
||||
|
||||
self._caches[ 'fullscreen' ] = ClientCaches.RenderedImageCache( 'fullscreen' )
|
||||
self._caches[ 'preview' ] = ClientCaches.RenderedImageCache( 'preview' )
|
||||
self._caches[ 'thumbnail' ] = ClientCaches.ThumbnailCache()
|
||||
self._caches[ 'fullscreen' ] = ClientCaches.RenderedImageCache( self, 'fullscreen' )
|
||||
self._caches[ 'preview' ] = ClientCaches.RenderedImageCache( self, 'preview' )
|
||||
self._caches[ 'thumbnail' ] = ClientCaches.ThumbnailCache( self )
|
||||
|
||||
CC.GlobalBMPs.STATICInitialise()
|
||||
|
||||
|
@ -555,6 +563,11 @@ class Controller( HydrusController.HydrusController ):
|
|||
|
||||
|
||||
|
||||
def MenuIsOpen( self ):
|
||||
|
||||
return self._menu_open
|
||||
|
||||
|
||||
def NotifyPubSubs( self ):
|
||||
|
||||
wx.CallAfter( self.ProcessPubSub )
|
||||
|
@ -570,6 +583,20 @@ class Controller( HydrusController.HydrusController ):
|
|||
return self._gui.PageHidden( page_key )
|
||||
|
||||
|
||||
def PopupMenu( self, window, menu ):
|
||||
|
||||
if menu.GetMenuItemCount() > 0:
|
||||
|
||||
self._menu_open = True
|
||||
|
||||
window.PopupMenu( menu )
|
||||
|
||||
self._menu_open = False
|
||||
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
|
||||
|
||||
def PrepStringForDisplay( self, text ):
|
||||
|
||||
if self._options[ 'gui_capitalisation' ]: return text
|
||||
|
|
|
@ -1155,6 +1155,8 @@ class DB( HydrusDB.HydrusDB ):
|
|||
self._c.execute( 'INSERT OR REPLACE INTO perceptual_hashes ( hash_id, phash ) VALUES ( ?, ? );', ( hash_id, sqlite3.Binary( phash ) ) )
|
||||
|
||||
|
||||
self._c.execute( 'DELETE FROM service_info WHERE info_type = ?;', ( HC.SERVICE_INFO_NUM_THUMBNAILS_LOCAL, ) )
|
||||
|
||||
hashes = { hash for ( hash, thumbnail ) in thumbnails }
|
||||
|
||||
self.pub_after_commit( 'new_thumbnails', hashes )
|
||||
|
@ -2186,12 +2188,15 @@ class DB( HydrusDB.HydrusDB ):
|
|||
current_counts = collections.defaultdict( zero )
|
||||
pending_counts = collections.defaultdict( zero )
|
||||
|
||||
current_counts.update( { tag_id : count for ( tag_id, count ) in self._c.execute( count_phrase + table_phrase + predicates_phrase + 'tag_id IN ' + HydrusData.SplayListForDB( tag_ids ) + ' GROUP BY tag_id;', ( HC.CURRENT, namespace_id ) ) } )
|
||||
pending_counts.update( { tag_id : count for ( tag_id, count ) in self._c.execute( count_phrase + table_phrase + predicates_phrase + 'tag_id IN ' + HydrusData.SplayListForDB( tag_ids ) + ' GROUP BY tag_id;', ( HC.PENDING, namespace_id ) ) } )
|
||||
for sub_tag_ids in HydrusData.SplitListIntoChunks( tag_ids, 50 ):
|
||||
|
||||
current_counts.update( { tag_id : count for ( tag_id, count ) in self._c.execute( count_phrase + table_phrase + predicates_phrase + 'tag_id IN ' + HydrusData.SplayListForDB( sub_tag_ids ) + ' GROUP BY tag_id;', ( HC.CURRENT, namespace_id ) ) } )
|
||||
pending_counts.update( { tag_id : count for ( tag_id, count ) in self._c.execute( count_phrase + table_phrase + predicates_phrase + 'tag_id IN ' + HydrusData.SplayListForDB( sub_tag_ids ) + ' GROUP BY tag_id;', ( HC.PENDING, namespace_id ) ) } )
|
||||
|
||||
|
||||
self._c.executemany( 'INSERT OR IGNORE INTO autocomplete_tags_cache ( file_service_id, tag_service_id, namespace_id, tag_id, current_count, pending_count ) VALUES ( ?, ?, ?, ?, ?, ? );', [ ( file_service_id, tag_service_id, namespace_id, tag_id, current_counts[ tag_id ], pending_counts[ tag_id ] ) for tag_id in tag_ids ] )
|
||||
self._c.executemany( 'INSERT OR IGNORE INTO autocomplete_tags_cache ( file_service_id, tag_service_id, namespace_id, tag_id, current_count, pending_count ) VALUES ( ?, ?, ?, ?, ?, ? );', ( ( file_service_id, tag_service_id, namespace_id, tag_id, current_counts[ tag_id ], pending_counts[ tag_id ] ) for tag_id in tag_ids ) )
|
||||
|
||||
cache_results.extend( [ ( namespace_id, tag_id, current_counts[ tag_id ], pending_counts[ tag_id ] ) for tag_id in tag_ids ] )
|
||||
cache_results.extend( ( ( namespace_id, tag_id, current_counts[ tag_id ], pending_counts[ tag_id ] ) for tag_id in tag_ids ) )
|
||||
|
||||
|
||||
#
|
||||
|
@ -2847,10 +2852,6 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
tags = siblings_manager.GetAllSiblings( tag )
|
||||
|
||||
tag_censorship_manager = self._controller.GetManager( 'tag_censorship' )
|
||||
|
||||
tags = tag_censorship_manager.FilterTags( tag_service_key, tags )
|
||||
|
||||
hash_ids = set()
|
||||
|
||||
predicates = []
|
||||
|
@ -3690,15 +3691,23 @@ class DB( HydrusDB.HydrusDB ):
|
|||
elif info_type == HC.SERVICE_INFO_NUM_THUMBNAILS: result = self._c.execute( 'SELECT COUNT( * ) FROM files_info WHERE service_id = ? AND mime IN ' + HydrusData.SplayListForDB( HC.MIMES_WITH_THUMBNAILS ) + ';', ( service_id, ) ).fetchone()
|
||||
elif info_type == HC.SERVICE_INFO_NUM_THUMBNAILS_LOCAL:
|
||||
|
||||
thumbnails_i_have = ClientFiles.GetAllThumbnailHashes()
|
||||
|
||||
hash_ids = [ hash_id for ( hash_id, ) in self._c.execute( 'SELECT hash_id FROM files_info WHERE mime IN ' + HydrusData.SplayListForDB( HC.MIMES_WITH_THUMBNAILS ) + ' AND service_id = ?;', ( service_id, ) ) ]
|
||||
|
||||
thumbnails_i_should_have = self._GetHashes( hash_ids )
|
||||
|
||||
thumbnails_i_have.intersection_update( thumbnails_i_should_have )
|
||||
num_local = 0
|
||||
|
||||
result = ( len( thumbnails_i_have ), )
|
||||
for hash in thumbnails_i_should_have:
|
||||
|
||||
path = ClientFiles.GetExpectedThumbnailPath( hash )
|
||||
|
||||
if os.path.exists( path ):
|
||||
|
||||
num_local += 1
|
||||
|
||||
|
||||
|
||||
result = ( num_local, )
|
||||
|
||||
elif info_type == HC.SERVICE_INFO_NUM_INBOX: result = self._c.execute( 'SELECT COUNT( * ) FROM file_inbox, files_info USING ( hash_id ) WHERE service_id = ?;', ( service_id, ) ).fetchone()
|
||||
|
||||
|
@ -4550,7 +4559,10 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
( new_namespace_id, new_tag_id ) = self._GetNamespaceIdTagId( new_tag )
|
||||
|
||||
except HydrusExceptions.SizeException: continue
|
||||
except HydrusExceptions.SizeException:
|
||||
|
||||
continue
|
||||
|
||||
|
||||
self._c.execute( 'DELETE FROM tag_siblings WHERE service_id = ? AND old_namespace_id = ? AND old_tag_id = ?;', ( service_id, old_namespace_id, old_tag_id ) )
|
||||
self._c.execute( 'DELETE FROM tag_sibling_petitions WHERE service_id = ? AND old_namespace_id = ? AND old_tag_id = ? AND status = ?;', ( service_id, old_namespace_id, old_tag_id, deletee_status ) )
|
||||
|
@ -4570,7 +4582,10 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
( new_namespace_id, new_tag_id ) = self._GetNamespaceIdTagId( new_tag )
|
||||
|
||||
except HydrusExceptions.SizeException: continue
|
||||
except HydrusExceptions.SizeException:
|
||||
|
||||
continue
|
||||
|
||||
|
||||
reason_id = self._GetReasonId( reason )
|
||||
|
||||
|
@ -4582,13 +4597,25 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
elif action in ( HC.CONTENT_UPDATE_RESCIND_PEND, HC.CONTENT_UPDATE_RESCIND_PETITION ):
|
||||
|
||||
if action == HC.CONTENT_UPDATE_RESCIND_PEND: deletee_status = HC.PENDING
|
||||
elif action == HC.CONTENT_UPDATE_RESCIND_PETITION: deletee_status = HC.PETITIONED
|
||||
if action == HC.CONTENT_UPDATE_RESCIND_PEND:
|
||||
|
||||
deletee_status = HC.PENDING
|
||||
|
||||
elif action == HC.CONTENT_UPDATE_RESCIND_PETITION:
|
||||
|
||||
deletee_status = HC.PETITIONED
|
||||
|
||||
|
||||
( old_tag, new_tag ) = row
|
||||
|
||||
try: ( old_namespace_id, old_tag_id ) = self._GetNamespaceIdTagId( old_tag )
|
||||
except HydrusExceptions.SizeException: continue
|
||||
try:
|
||||
|
||||
( old_namespace_id, old_tag_id ) = self._GetNamespaceIdTagId( old_tag )
|
||||
|
||||
except HydrusExceptions.SizeException:
|
||||
|
||||
continue
|
||||
|
||||
|
||||
self._c.execute( 'DELETE FROM tag_sibling_petitions WHERE service_id = ? AND old_namespace_id = ? AND old_tag_id = ? AND status = ?;', ( service_id, old_namespace_id, old_tag_id, deletee_status ) )
|
||||
|
||||
|
@ -6114,6 +6141,44 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
|
||||
|
||||
if version == 182:
|
||||
|
||||
hash_ids = { hash_id for ( hash_id, ) in self._c.execute( 'SELECT hash_id FROM files_info WHERE mime = ?;', ( HC.APPLICATION_FLASH, ) ) }
|
||||
|
||||
num_done = 0
|
||||
|
||||
num_to_do = len( hash_ids )
|
||||
|
||||
for hash_id in hash_ids:
|
||||
|
||||
num_done += 1
|
||||
|
||||
if num_done % 10 == 0:
|
||||
|
||||
self._controller.pub( 'splash_set_status_text', 'updating flash thumbnails: ' + HydrusData.ConvertValueRangeToPrettyString( num_done, num_to_do ) )
|
||||
|
||||
|
||||
hash = self._GetHash( hash_id )
|
||||
|
||||
try:
|
||||
|
||||
file_path = ClientFiles.GetFilePath( hash, HC.APPLICATION_FLASH )
|
||||
|
||||
except HydrusExceptions.NotFoundException:
|
||||
|
||||
continue
|
||||
|
||||
|
||||
thumbnail = HydrusFileHandling.GenerateThumbnail( file_path )
|
||||
|
||||
self._AddThumbnails( [ ( hash, thumbnail ) ] )
|
||||
|
||||
|
||||
#
|
||||
|
||||
self._c.execute( 'DELETE FROM service_info WHERE info_type IN ( ?, ? );', ( HC.SERVICE_INFO_NUM_THUMBNAILS, HC.SERVICE_INFO_NUM_THUMBNAILS_LOCAL ) )
|
||||
|
||||
|
||||
self._controller.pub( 'splash_set_title_text', 'updating db to v' + str( version + 1 ) )
|
||||
|
||||
self._c.execute( 'UPDATE version SET version = ?;', ( version + 1, ) )
|
||||
|
|
|
@ -7,6 +7,7 @@ import collections
|
|||
import datetime
|
||||
import HydrusConstants as HC
|
||||
import HydrusExceptions
|
||||
import HydrusPaths
|
||||
import HydrusSerialisable
|
||||
import HydrusTags
|
||||
import threading
|
||||
|
@ -175,11 +176,11 @@ def DeletePath( path ):
|
|||
|
||||
if HC.options[ 'delete_to_recycle_bin' ] == True:
|
||||
|
||||
HydrusData.RecyclePath( path )
|
||||
HydrusPaths.RecyclePath( path )
|
||||
|
||||
else:
|
||||
|
||||
HydrusData.DeletePath( path )
|
||||
HydrusPaths.DeletePath( path )
|
||||
|
||||
|
||||
def GetMediasTagCount( pool, tag_service_key = CC.COMBINED_TAG_SERVICE_KEY, collapse_siblings = False ):
|
||||
|
@ -352,6 +353,8 @@ class ClientOptions( HydrusSerialisable.SerialisableBase ):
|
|||
self._dictionary[ 'booleans' ][ 'apply_all_parents_to_all_services' ] = False
|
||||
self._dictionary[ 'booleans' ][ 'apply_all_siblings_to_all_services' ] = False
|
||||
|
||||
self._dictionary[ 'client_files_locations_ideal_weights' ] = [ ( HydrusPaths.ConvertAbsPathToPortablePath( HC.CLIENT_FILES_DIR ), 1.0 ) ]
|
||||
|
||||
|
||||
def _InitialiseFromSerialisableInfo( self, serialisable_info ):
|
||||
|
||||
|
@ -379,6 +382,20 @@ class ClientOptions( HydrusSerialisable.SerialisableBase ):
|
|||
|
||||
|
||||
|
||||
def GetClientFilesLocationsToIdealWeights( self ):
|
||||
|
||||
result = {}
|
||||
|
||||
for ( portable_path, weight ) in self._dictionary[ 'client_files_locations_ideal_weights' ]:
|
||||
|
||||
abs_path = HydrusPaths.ConvertPortablePathToAbsPath( portable_path )
|
||||
|
||||
result[ abs_path ] = weight
|
||||
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def GetDefaultImportTagOptions( self, gallery_identifier = None ):
|
||||
|
||||
with self._lock:
|
||||
|
@ -2285,13 +2302,21 @@ class Service( HydrusData.HydrusYAMLBase ):
|
|||
HydrusGlobals.client_controller.pub( 'splash_set_status_text', 'reviewing thumbnails' )
|
||||
job_key.SetVariable( 'popup_text_1', 'reviewing existing thumbnails' )
|
||||
|
||||
thumbnail_hashes_i_have = ClientFiles.GetAllThumbnailHashes()
|
||||
|
||||
job_key.SetVariable( 'popup_text_1', 'reviewing service thumbnails' )
|
||||
|
||||
thumbnail_hashes_i_should_have = HydrusGlobals.client_controller.Read( 'thumbnail_hashes_i_should_have', self._service_key )
|
||||
|
||||
thumbnail_hashes_i_need = thumbnail_hashes_i_should_have.difference( thumbnail_hashes_i_have )
|
||||
thumbnail_hashes_i_need = set()
|
||||
|
||||
for hash in thumbnail_hashes_i_should_have:
|
||||
|
||||
path = ClientFiles.GetExpectedThumbnailPath( hash )
|
||||
|
||||
if not os.path.exists( path ):
|
||||
|
||||
thumbnail_hashes_i_need.add( hash )
|
||||
|
||||
|
||||
|
||||
if len( thumbnail_hashes_i_need ) > 0:
|
||||
|
||||
|
@ -2378,48 +2403,6 @@ class Service( HydrusData.HydrusYAMLBase ):
|
|||
|
||||
def ToTuple( self ): return ( self._service_key, self._service_type, self._name, self._info )
|
||||
|
||||
class ServicesManager( object ):
|
||||
|
||||
def __init__( self ):
|
||||
|
||||
self._lock = threading.Lock()
|
||||
self._keys_to_services = {}
|
||||
self._services_sorted = []
|
||||
|
||||
self.RefreshServices()
|
||||
|
||||
HydrusGlobals.client_controller.sub( self, 'RefreshServices', 'notify_new_services_data' )
|
||||
|
||||
|
||||
def GetService( self, service_key ):
|
||||
|
||||
with self._lock:
|
||||
|
||||
try: return self._keys_to_services[ service_key ]
|
||||
except KeyError: raise HydrusExceptions.NotFoundException( 'That service was not found!' )
|
||||
|
||||
|
||||
|
||||
def GetServices( self, types = HC.ALL_SERVICES ):
|
||||
|
||||
with self._lock: return [ service for service in self._services_sorted if service.GetServiceType() in types ]
|
||||
|
||||
|
||||
def RefreshServices( self ):
|
||||
|
||||
with self._lock:
|
||||
|
||||
services = HydrusGlobals.client_controller.Read( 'services' )
|
||||
|
||||
self._keys_to_services = { service.GetServiceKey() : service for service in services }
|
||||
|
||||
compare_function = lambda a, b: cmp( a.GetName(), b.GetName() )
|
||||
|
||||
self._services_sorted = list( services )
|
||||
self._services_sorted.sort( cmp = compare_function )
|
||||
|
||||
|
||||
|
||||
class Shortcuts( HydrusSerialisable.SerialisableBaseNamed ):
|
||||
|
||||
SERIALISABLE_TYPE = HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUTS
|
||||
|
@ -2579,228 +2562,6 @@ class Shortcuts( HydrusSerialisable.SerialisableBaseNamed ):
|
|||
|
||||
HydrusSerialisable.SERIALISABLE_TYPES_TO_OBJECT_TYPES[ HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUTS ] = Shortcuts
|
||||
|
||||
class UndoManager( object ):
|
||||
|
||||
def __init__( self ):
|
||||
|
||||
self._commands = []
|
||||
self._inverted_commands = []
|
||||
self._current_index = 0
|
||||
|
||||
self._lock = threading.Lock()
|
||||
|
||||
HydrusGlobals.client_controller.sub( self, 'Undo', 'undo' )
|
||||
HydrusGlobals.client_controller.sub( self, 'Redo', 'redo' )
|
||||
|
||||
|
||||
def _FilterServiceKeysToContentUpdates( self, service_keys_to_content_updates ):
|
||||
|
||||
filtered_service_keys_to_content_updates = {}
|
||||
|
||||
for ( service_key, content_updates ) in service_keys_to_content_updates.items():
|
||||
|
||||
filtered_content_updates = []
|
||||
|
||||
for content_update in content_updates:
|
||||
|
||||
( data_type, action, row ) = content_update.ToTuple()
|
||||
|
||||
if data_type == HC.CONTENT_TYPE_FILES:
|
||||
if action in ( HC.CONTENT_UPDATE_ADD, HC.CONTENT_UPDATE_DELETE, HC.CONTENT_UPDATE_UNDELETE, HC.CONTENT_UPDATE_RESCIND_PETITION ): continue
|
||||
elif data_type == HC.CONTENT_TYPE_MAPPINGS:
|
||||
|
||||
if action in ( HC.CONTENT_UPDATE_RESCIND_PETITION, HC.CONTENT_UPDATE_ADVANCED ): continue
|
||||
|
||||
else: continue
|
||||
|
||||
filtered_content_update = HydrusData.ContentUpdate( data_type, action, row )
|
||||
|
||||
filtered_content_updates.append( filtered_content_update )
|
||||
|
||||
|
||||
if len( filtered_content_updates ) > 0:
|
||||
|
||||
filtered_service_keys_to_content_updates[ service_key ] = filtered_content_updates
|
||||
|
||||
|
||||
|
||||
return filtered_service_keys_to_content_updates
|
||||
|
||||
|
||||
def _InvertServiceKeysToContentUpdates( self, service_keys_to_content_updates ):
|
||||
|
||||
inverted_service_keys_to_content_updates = {}
|
||||
|
||||
for ( service_key, content_updates ) in service_keys_to_content_updates.items():
|
||||
|
||||
inverted_content_updates = []
|
||||
|
||||
for content_update in content_updates:
|
||||
|
||||
( data_type, action, row ) = content_update.ToTuple()
|
||||
|
||||
inverted_row = row
|
||||
|
||||
if data_type == HC.CONTENT_TYPE_FILES:
|
||||
|
||||
if action == HC.CONTENT_UPDATE_ARCHIVE: inverted_action = HC.CONTENT_UPDATE_INBOX
|
||||
elif action == HC.CONTENT_UPDATE_INBOX: inverted_action = HC.CONTENT_UPDATE_ARCHIVE
|
||||
elif action == HC.CONTENT_UPDATE_PEND: inverted_action = HC.CONTENT_UPDATE_RESCIND_PEND
|
||||
elif action == HC.CONTENT_UPDATE_RESCIND_PEND: inverted_action = HC.CONTENT_UPDATE_PEND
|
||||
elif action == HC.CONTENT_UPDATE_PETITION:
|
||||
|
||||
inverted_action = HC.CONTENT_UPDATE_RESCIND_PETITION
|
||||
|
||||
( hashes, reason ) = row
|
||||
|
||||
inverted_row = hashes
|
||||
|
||||
|
||||
elif data_type == HC.CONTENT_TYPE_MAPPINGS:
|
||||
|
||||
if action == HC.CONTENT_UPDATE_ADD: inverted_action = HC.CONTENT_UPDATE_DELETE
|
||||
elif action == HC.CONTENT_UPDATE_DELETE: inverted_action = HC.CONTENT_UPDATE_ADD
|
||||
elif action == HC.CONTENT_UPDATE_PEND: inverted_action = HC.CONTENT_UPDATE_RESCIND_PEND
|
||||
elif action == HC.CONTENT_UPDATE_RESCIND_PEND: inverted_action = HC.CONTENT_UPDATE_PEND
|
||||
elif action == HC.CONTENT_UPDATE_PETITION:
|
||||
|
||||
inverted_action = HC.CONTENT_UPDATE_RESCIND_PETITION
|
||||
|
||||
( tag, hashes, reason ) = row
|
||||
|
||||
inverted_row = ( tag, hashes )
|
||||
|
||||
|
||||
|
||||
inverted_content_update = HydrusData.ContentUpdate( data_type, inverted_action, inverted_row )
|
||||
|
||||
inverted_content_updates.append( inverted_content_update )
|
||||
|
||||
|
||||
inverted_service_keys_to_content_updates[ service_key ] = inverted_content_updates
|
||||
|
||||
|
||||
return inverted_service_keys_to_content_updates
|
||||
|
||||
|
||||
def AddCommand( self, action, *args, **kwargs ):
|
||||
|
||||
with self._lock:
|
||||
|
||||
inverted_action = action
|
||||
inverted_args = args
|
||||
inverted_kwargs = kwargs
|
||||
|
||||
if action == 'content_updates':
|
||||
|
||||
( service_keys_to_content_updates, ) = args
|
||||
|
||||
service_keys_to_content_updates = self._FilterServiceKeysToContentUpdates( service_keys_to_content_updates )
|
||||
|
||||
if len( service_keys_to_content_updates ) == 0: return
|
||||
|
||||
inverted_service_keys_to_content_updates = self._InvertServiceKeysToContentUpdates( service_keys_to_content_updates )
|
||||
|
||||
if len( inverted_service_keys_to_content_updates ) == 0: return
|
||||
|
||||
inverted_args = ( inverted_service_keys_to_content_updates, )
|
||||
|
||||
else: return
|
||||
|
||||
self._commands = self._commands[ : self._current_index ]
|
||||
self._inverted_commands = self._inverted_commands[ : self._current_index ]
|
||||
|
||||
self._commands.append( ( action, args, kwargs ) )
|
||||
|
||||
self._inverted_commands.append( ( inverted_action, inverted_args, inverted_kwargs ) )
|
||||
|
||||
self._current_index += 1
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'notify_new_undo' )
|
||||
|
||||
|
||||
|
||||
def GetUndoRedoStrings( self ):
|
||||
|
||||
with self._lock:
|
||||
|
||||
( undo_string, redo_string ) = ( None, None )
|
||||
|
||||
if self._current_index > 0:
|
||||
|
||||
undo_index = self._current_index - 1
|
||||
|
||||
( action, args, kwargs ) = self._commands[ undo_index ]
|
||||
|
||||
if action == 'content_updates':
|
||||
|
||||
( service_keys_to_content_updates, ) = args
|
||||
|
||||
undo_string = 'undo ' + ConvertServiceKeysToContentUpdatesToPrettyString( service_keys_to_content_updates )
|
||||
|
||||
|
||||
|
||||
if len( self._commands ) > 0 and self._current_index < len( self._commands ):
|
||||
|
||||
redo_index = self._current_index
|
||||
|
||||
( action, args, kwargs ) = self._commands[ redo_index ]
|
||||
|
||||
if action == 'content_updates':
|
||||
|
||||
( service_keys_to_content_updates, ) = args
|
||||
|
||||
redo_string = 'redo ' + ConvertServiceKeysToContentUpdatesToPrettyString( service_keys_to_content_updates )
|
||||
|
||||
|
||||
|
||||
return ( undo_string, redo_string )
|
||||
|
||||
|
||||
|
||||
def Undo( self ):
|
||||
|
||||
action = None
|
||||
|
||||
with self._lock:
|
||||
|
||||
if self._current_index > 0:
|
||||
|
||||
self._current_index -= 1
|
||||
|
||||
( action, args, kwargs ) = self._inverted_commands[ self._current_index ]
|
||||
|
||||
|
||||
if action is not None:
|
||||
|
||||
HydrusGlobals.client_controller.WriteSynchronous( action, *args, **kwargs )
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'notify_new_undo' )
|
||||
|
||||
|
||||
|
||||
def Redo( self ):
|
||||
|
||||
action = None
|
||||
|
||||
with self._lock:
|
||||
|
||||
if len( self._commands ) > 0 and self._current_index < len( self._commands ):
|
||||
|
||||
( action, args, kwargs ) = self._commands[ self._current_index ]
|
||||
|
||||
self._current_index += 1
|
||||
|
||||
|
||||
|
||||
if action is not None:
|
||||
|
||||
HydrusGlobals.client_controller.WriteSynchronous( action, *args, **kwargs )
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'notify_new_undo' )
|
||||
|
||||
|
||||
|
||||
def GetShortcutFromEvent( event ):
|
||||
|
||||
modifier = wx.ACCEL_NORMAL
|
||||
|
|
|
@ -6,6 +6,7 @@ import HydrusData
|
|||
import HydrusExceptions
|
||||
import HydrusFileHandling
|
||||
import HydrusGlobals
|
||||
import HydrusPaths
|
||||
import HydrusSerialisable
|
||||
import itertools
|
||||
import os
|
||||
|
@ -109,17 +110,9 @@ def GetAllThumbnailHashes():
|
|||
|
||||
thumbnail_hashes = set()
|
||||
|
||||
for path in IterateAllThumbnailPaths():
|
||||
for hash in IterateAllThumbnailHashes():
|
||||
|
||||
( base, filename ) = os.path.split( path )
|
||||
|
||||
if not filename.endswith( '_resized' ):
|
||||
|
||||
try: hash = filename.decode( 'hex' )
|
||||
except TypeError: continue
|
||||
|
||||
thumbnail_hashes.add( hash )
|
||||
|
||||
thumbnail_hashes.add( hash )
|
||||
|
||||
|
||||
return thumbnail_hashes
|
||||
|
@ -150,7 +143,7 @@ def GetExportPath():
|
|||
|
||||
path = os.path.normpath( path ) # converts slashes to backslashes for windows
|
||||
|
||||
path = HydrusData.ConvertPortablePathToAbsPath( path )
|
||||
path = HydrusPaths.ConvertPortablePathToAbsPath( path )
|
||||
|
||||
return path
|
||||
|
||||
|
@ -172,9 +165,15 @@ def GetFilePath( hash, mime = None ):
|
|||
|
||||
|
||||
|
||||
else: path = GetExpectedFilePath( hash, mime )
|
||||
else:
|
||||
|
||||
path = GetExpectedFilePath( hash, mime )
|
||||
|
||||
|
||||
if path is None or not os.path.exists( path ): raise HydrusExceptions.NotFoundException( 'File not found!' )
|
||||
if path is None or not os.path.exists( path ):
|
||||
|
||||
raise HydrusExceptions.NotFoundException( 'File not found!' )
|
||||
|
||||
|
||||
return path
|
||||
|
||||
|
@ -199,7 +198,10 @@ def GetThumbnailPath( hash, full_size = True ):
|
|||
|
||||
if not os.path.exists( path ):
|
||||
|
||||
if full_size: raise HydrusExceptions.NotFoundException( 'Thumbnail not found!' )
|
||||
if full_size:
|
||||
|
||||
raise HydrusExceptions.NotFoundException( 'Thumbnail not found!' )
|
||||
|
||||
else:
|
||||
|
||||
full_size_path = GetThumbnailPath( hash, True )
|
||||
|
@ -216,7 +218,10 @@ def GetThumbnailPath( hash, full_size = True ):
|
|||
|
||||
thumbnail_resized = HydrusFileHandling.GenerateThumbnail( full_size_path, thumbnail_dimensions )
|
||||
|
||||
with open( path, 'wb' ) as f: f.write( thumbnail_resized )
|
||||
with open( path, 'wb' ) as f:
|
||||
|
||||
f.write( thumbnail_resized )
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -269,6 +274,21 @@ def IterateAllFilePaths():
|
|||
|
||||
|
||||
|
||||
def IterateAllThumbnailHashes():
|
||||
|
||||
for path in IterateAllThumbnailPaths():
|
||||
|
||||
( base, filename ) = os.path.split( path )
|
||||
|
||||
if not filename.endswith( '_resized' ):
|
||||
|
||||
try: hash = filename.decode( 'hex' )
|
||||
except TypeError: continue
|
||||
|
||||
yield hash
|
||||
|
||||
|
||||
|
||||
def IterateAllThumbnailPaths():
|
||||
|
||||
hex_chars = '0123456789abcdef'
|
||||
|
|
|
@ -1026,11 +1026,14 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
menu.AppendMenu( wx.ID_NONE, p( 'Links' ), links )
|
||||
|
||||
db_profile_mode_id = ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'db_profile_mode' )
|
||||
pubsub_profile_mode_id = ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'pubsub_profile_mode' )
|
||||
special_debug_mode_id = ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'special_debug_mode' )
|
||||
|
||||
debug = wx.Menu()
|
||||
debug.AppendCheckItem( db_profile_mode_id, p( '&DB Profile Mode' ) )
|
||||
debug.Check( db_profile_mode_id, HydrusGlobals.db_profile_mode )
|
||||
debug.AppendCheckItem( pubsub_profile_mode_id, p( '&PubSub Profile Mode' ) )
|
||||
debug.Check( pubsub_profile_mode_id, HydrusGlobals.pubsub_profile_mode )
|
||||
debug.AppendCheckItem( special_debug_mode_id, p( '&Special Debug Mode' ) )
|
||||
debug.Check( special_debug_mode_id, HydrusGlobals.special_debug_mode )
|
||||
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'force_idle' ), p( 'Force Idle Mode' ) )
|
||||
|
@ -1293,7 +1296,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
initial_media_results = []
|
||||
|
||||
|
||||
page = ClientGUIPages.Page( self._notebook, management_controller, initial_media_results )
|
||||
page = ClientGUIPages.Page( self._notebook, self._controller, management_controller, initial_media_results )
|
||||
|
||||
self._notebook.AddPage( page, page_name, select = True )
|
||||
|
||||
|
@ -1860,6 +1863,10 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
|
||||
job_key.SetVariable( 'popup_text_1', service.GetName() + ' was busy. please try again in a few minutes' )
|
||||
|
||||
job_key.DeleteVariable( 'popup_gauge_1' )
|
||||
|
||||
job_key.Cancel()
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
@ -1921,6 +1928,10 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
|
||||
job_key.SetVariable( 'popup_text_1', service.GetName() + ' was busy. please try again in a few minutes' )
|
||||
|
||||
job_key.DeleteVariable( 'popup_gauge_1' )
|
||||
|
||||
job_key.Cancel()
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
@ -1932,12 +1943,15 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
|
||||
except Exception as e:
|
||||
|
||||
job_key.SetVariable( 'popup_text_1', service.GetName() + ' error' )
|
||||
|
||||
job_key.DeleteVariable( 'popup_gauge_1' )
|
||||
|
||||
job_key.Cancel()
|
||||
|
||||
raise
|
||||
|
||||
|
||||
job_key.DeleteVariable( 'popup_gauge_1' )
|
||||
job_key.SetVariable( 'popup_text_1', prefix + 'upload done!' )
|
||||
|
||||
HydrusData.Print( job_key.ToString() )
|
||||
|
@ -2139,6 +2153,10 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
elif command == 'pause_subs_sync': self._PauseSync( 'subs' )
|
||||
elif command == 'petitions': self._NewPagePetitions( data )
|
||||
elif command == 'post_news': self._PostNews( data )
|
||||
elif command == 'pubsub_profile_mode':
|
||||
|
||||
HydrusGlobals.pubsub_profile_mode = not HydrusGlobals.pubsub_profile_mode
|
||||
|
||||
elif command == 'redo': self._controller.pub( 'redo' )
|
||||
elif command == 'refresh':
|
||||
|
||||
|
@ -2193,9 +2211,7 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'tab_menu_close_page' ), 'close page' )
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'tab_menu_rename_page' ), 'rename page' )
|
||||
|
||||
self.PopupMenu( menu )
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
self._controller.PopupMenu( self, menu )
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -833,10 +833,13 @@ class Canvas( object ):
|
|||
|
||||
|
||||
def _ManageRatings( self ):
|
||||
|
||||
if self._current_media is not None:
|
||||
|
||||
if len( HydrusGlobals.client_controller.GetServicesManager().GetServices( HC.RATINGS_SERVICES ) ) > 0:
|
||||
|
||||
with ClientGUIDialogsManage.DialogManageRatings( self, ( self._current_display_media, ) ) as dlg: dlg.ShowModal()
|
||||
if self._current_media is not None:
|
||||
|
||||
with ClientGUIDialogsManage.DialogManageRatings( self, ( self._current_display_media, ) ) as dlg: dlg.ShowModal()
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1380,7 +1383,7 @@ class CanvasWithDetails( Canvas ):
|
|||
|
||||
services_manager = HydrusGlobals.client_controller.GetServicesManager()
|
||||
|
||||
like_services = services_manager.GetServices( ( HC.LOCAL_RATING_LIKE, ) )
|
||||
like_services = services_manager.GetServices( ( HC.LOCAL_RATING_LIKE, ), randomised = False )
|
||||
|
||||
like_services.reverse()
|
||||
|
||||
|
@ -1400,7 +1403,7 @@ class CanvasWithDetails( Canvas ):
|
|||
if len( like_services ) > 0: current_y += 20
|
||||
|
||||
|
||||
numerical_services = services_manager.GetServices( ( HC.LOCAL_RATING_NUMERICAL, ) )
|
||||
numerical_services = services_manager.GetServices( ( HC.LOCAL_RATING_NUMERICAL, ), randomised = False )
|
||||
|
||||
for numerical_service in numerical_services:
|
||||
|
||||
|
@ -1580,11 +1583,7 @@ class CanvasPanel( Canvas, wx.Window ):
|
|||
|
||||
menu.AppendMenu( CC.ID_NULL, 'share', share_menu )
|
||||
|
||||
self.PopupMenu( menu )
|
||||
|
||||
self._menu_open = False
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
event.Skip()
|
||||
|
||||
|
@ -1630,8 +1629,6 @@ class CanvasFullscreenMediaList( ClientMedia.ListeningMediaList, CanvasWithDetai
|
|||
|
||||
self._page_key = page_key
|
||||
|
||||
self._menu_open = False
|
||||
|
||||
self._just_started = True
|
||||
|
||||
self.Show( True )
|
||||
|
@ -1946,7 +1943,7 @@ class CanvasFullscreenMediaList( ClientMedia.ListeningMediaList, CanvasWithDetai
|
|||
return
|
||||
|
||||
|
||||
if self._menu_open:
|
||||
if HydrusGlobals.client_controller.MenuIsOpen():
|
||||
|
||||
self._timer_cursor_hide.Start( 800, wx.TIMER_ONE_SHOT )
|
||||
|
||||
|
@ -2652,25 +2649,19 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaListNavigable ):
|
|||
if self.IsFullScreen(): menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'fullscreen_switch' ), 'exit fullscreen' )
|
||||
else: menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'fullscreen_switch' ), 'go fullscreen' )
|
||||
|
||||
self._menu_open = True
|
||||
|
||||
if self._timer_slideshow.IsRunning():
|
||||
|
||||
self._timer_slideshow.Stop()
|
||||
|
||||
self.PopupMenu( menu )
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
self._timer_slideshow.Start()
|
||||
|
||||
else:
|
||||
|
||||
self.PopupMenu( menu )
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
|
||||
self._menu_open = False
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
|
||||
event.Skip()
|
||||
|
||||
|
||||
|
@ -3063,13 +3054,7 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaListNavigable
|
|||
if self.IsFullScreen(): menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'fullscreen_switch' ), 'exit fullscreen' )
|
||||
else: menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'fullscreen_switch' ), 'go fullscreen' )
|
||||
|
||||
self._menu_open = True
|
||||
|
||||
self.PopupMenu( menu )
|
||||
|
||||
self._menu_open = False
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
event.Skip()
|
||||
|
||||
|
|
|
@ -32,6 +32,44 @@ ID_TIMER_DROPDOWN_HIDE = wx.NewId()
|
|||
ID_TIMER_AC_LAG = wx.NewId()
|
||||
ID_TIMER_POPUP = wx.NewId()
|
||||
|
||||
def FlushOutPredicates( parent, predicates ):
|
||||
|
||||
good_predicates = []
|
||||
|
||||
for predicate in predicates:
|
||||
|
||||
predicate = predicate.GetCountlessCopy()
|
||||
|
||||
( predicate_type, value, inclusive ) = predicate.GetInfo()
|
||||
|
||||
if value is None and predicate_type in [ HC.PREDICATE_TYPE_SYSTEM_NUM_TAGS, HC.PREDICATE_TYPE_SYSTEM_LIMIT, HC.PREDICATE_TYPE_SYSTEM_SIZE, HC.PREDICATE_TYPE_SYSTEM_DIMENSIONS, HC.PREDICATE_TYPE_SYSTEM_AGE, HC.PREDICATE_TYPE_SYSTEM_HASH, HC.PREDICATE_TYPE_SYSTEM_DURATION, HC.PREDICATE_TYPE_SYSTEM_NUM_WORDS, HC.PREDICATE_TYPE_SYSTEM_MIME, HC.PREDICATE_TYPE_SYSTEM_RATING, HC.PREDICATE_TYPE_SYSTEM_SIMILAR_TO, HC.PREDICATE_TYPE_SYSTEM_FILE_SERVICE ]:
|
||||
|
||||
import ClientGUIDialogs
|
||||
|
||||
with ClientGUIDialogs.DialogInputFileSystemPredicates( parent, predicate_type ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
|
||||
good_predicates.extend( dlg.GetPredicates() )
|
||||
|
||||
else:
|
||||
|
||||
continue
|
||||
|
||||
|
||||
|
||||
elif predicate_type == HC.PREDICATE_TYPE_SYSTEM_UNTAGGED:
|
||||
|
||||
good_predicates.append( ClientData.Predicate( HC.PREDICATE_TYPE_SYSTEM_NUM_TAGS, ( '=', 0 ) ) )
|
||||
|
||||
else:
|
||||
|
||||
good_predicates.append( predicate )
|
||||
|
||||
|
||||
|
||||
return good_predicates
|
||||
|
||||
def IsWXAncestor( child, ancestor ):
|
||||
|
||||
parent = child
|
||||
|
@ -108,6 +146,7 @@ class AutoCompleteDropdown( wx.Panel ):
|
|||
wx.Panel.__init__( self, parent )
|
||||
|
||||
self._last_search_text = ''
|
||||
self._next_updatelist_is_probably_fast = False
|
||||
|
||||
tlp = self.GetTopLevelParent()
|
||||
|
||||
|
@ -463,7 +502,7 @@ class AutoCompleteDropdown( wx.Panel ):
|
|||
|
||||
( char_limit, long_wait, short_wait ) = HC.options[ 'ac_timings' ]
|
||||
|
||||
if num_chars == 0: self._UpdateList()
|
||||
if num_chars == 0 or self._next_updatelist_is_probably_fast: self._UpdateList()
|
||||
elif num_chars < char_limit: self._lag_timer.Start( long_wait, wx.TIMER_ONE_SHOT )
|
||||
else: self._lag_timer.Start( short_wait, wx.TIMER_ONE_SHOT )
|
||||
|
||||
|
@ -524,6 +563,8 @@ class AutoCompleteDropdownTags( AutoCompleteDropdown ):
|
|||
self._current_namespace = ''
|
||||
self._current_matches = []
|
||||
|
||||
self._cached_results = []
|
||||
|
||||
self._file_service_key = file_service_key
|
||||
self._tag_service_key = tag_service_key
|
||||
|
||||
|
@ -594,9 +635,7 @@ class AutoCompleteDropdownTags( AutoCompleteDropdown ):
|
|||
|
||||
for service in services: menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'change_file_repository', service.GetServiceKey() ), service.GetName() )
|
||||
|
||||
self._file_repo_button.PopupMenu( menu )
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
HydrusGlobals.client_controller.PopupMenu( self._file_repo_button, menu )
|
||||
|
||||
|
||||
def EventMenu( self, event ):
|
||||
|
@ -636,9 +675,7 @@ class AutoCompleteDropdownTags( AutoCompleteDropdown ):
|
|||
|
||||
for service in services: menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'change_tag_repository', service.GetServiceKey() ), service.GetName() )
|
||||
|
||||
self._tag_repo_button.PopupMenu( menu )
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
HydrusGlobals.client_controller.PopupMenu( self._tag_repo_button, menu )
|
||||
|
||||
|
||||
class AutoCompleteDropdownTagsRead( AutoCompleteDropdownTags ):
|
||||
|
@ -693,41 +730,7 @@ class AutoCompleteDropdownTagsRead( AutoCompleteDropdownTags ):
|
|||
self._text_ctrl.SetValue( '' )
|
||||
|
||||
|
||||
entry_predicates = []
|
||||
|
||||
for predicate in predicates:
|
||||
|
||||
predicate = predicate.GetCountlessCopy()
|
||||
|
||||
( predicate_type, value, inclusive ) = predicate.GetInfo()
|
||||
|
||||
if predicate_type in [ HC.PREDICATE_TYPE_SYSTEM_NUM_TAGS, HC.PREDICATE_TYPE_SYSTEM_LIMIT, HC.PREDICATE_TYPE_SYSTEM_SIZE, HC.PREDICATE_TYPE_SYSTEM_DIMENSIONS, HC.PREDICATE_TYPE_SYSTEM_AGE, HC.PREDICATE_TYPE_SYSTEM_HASH, HC.PREDICATE_TYPE_SYSTEM_DURATION, HC.PREDICATE_TYPE_SYSTEM_NUM_WORDS, HC.PREDICATE_TYPE_SYSTEM_MIME, HC.PREDICATE_TYPE_SYSTEM_RATING, HC.PREDICATE_TYPE_SYSTEM_SIMILAR_TO, HC.PREDICATE_TYPE_SYSTEM_FILE_SERVICE ]:
|
||||
|
||||
import ClientGUIDialogs
|
||||
|
||||
with ClientGUIDialogs.DialogInputFileSystemPredicates( self, predicate_type ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
|
||||
entry_predicates.extend( dlg.GetPredicates() )
|
||||
|
||||
else:
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
elif predicate_type == HC.PREDICATE_TYPE_SYSTEM_UNTAGGED:
|
||||
|
||||
entry_predicates.append( ClientData.Predicate( HC.PREDICATE_TYPE_SYSTEM_NUM_TAGS, ( '=', 0 ) ) )
|
||||
|
||||
else:
|
||||
|
||||
entry_predicates.append( predicate )
|
||||
|
||||
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'enter_predicates', self._page_key, entry_predicates )
|
||||
HydrusGlobals.client_controller.pub( 'enter_predicates', self._page_key, predicates )
|
||||
|
||||
|
||||
def _BroadcastCurrentText( self ):
|
||||
|
@ -786,6 +789,8 @@ class AutoCompleteDropdownTagsRead( AutoCompleteDropdownTags ):
|
|||
|
||||
def _GenerateMatches( self ):
|
||||
|
||||
self._next_updatelist_is_probably_fast = False
|
||||
|
||||
num_autocomplete_chars = HC.options[ 'num_autocomplete_chars' ]
|
||||
|
||||
( inclusive, search_text, entry_predicate ) = self._ParseSearchText()
|
||||
|
@ -808,7 +813,7 @@ class AutoCompleteDropdownTagsRead( AutoCompleteDropdownTags ):
|
|||
|
||||
if ':' in search_text:
|
||||
|
||||
( namespace, half_complete_tag ) = search_text.split( ':' )
|
||||
( namespace, half_complete_tag ) = search_text.split( ':', 1 )
|
||||
|
||||
if namespace != self._current_namespace:
|
||||
|
||||
|
@ -853,6 +858,8 @@ class AutoCompleteDropdownTagsRead( AutoCompleteDropdownTags ):
|
|||
|
||||
predicates = HydrusGlobals.client_controller.Read( 'autocomplete_predicates', file_service_key = self._file_service_key, tag_service_key = self._tag_service_key, tag = search_text, include_current = self._include_current, include_pending = self._include_pending, add_namespaceless = True )
|
||||
|
||||
predicates = ClientSearch.SortPredicates( predicates, collapse_siblings = True )
|
||||
|
||||
else:
|
||||
|
||||
if must_do_a_search or self._cache_text == '' or not search_text.startswith( self._cache_text ):
|
||||
|
@ -861,9 +868,13 @@ class AutoCompleteDropdownTagsRead( AutoCompleteDropdownTags ):
|
|||
|
||||
self._cached_results = HydrusGlobals.client_controller.Read( 'autocomplete_predicates', file_service_key = self._file_service_key, tag_service_key = self._tag_service_key, half_complete_tag = search_text, include_current = self._include_current, include_pending = self._include_pending, add_namespaceless = True )
|
||||
|
||||
self._cached_results = ClientSearch.SortPredicates( self._cached_results, collapse_siblings = False )
|
||||
|
||||
|
||||
predicates = self._cached_results
|
||||
|
||||
self._next_updatelist_is_probably_fast = True
|
||||
|
||||
|
||||
else:
|
||||
|
||||
|
@ -897,8 +908,10 @@ class AutoCompleteDropdownTagsRead( AutoCompleteDropdownTags ):
|
|||
|
||||
predicates = [ ClientData.Predicate( HC.PREDICATE_TYPE_TAG, tag, inclusive = inclusive, counts = { HC.CURRENT : current_tags_to_count[ tag ], HC.PENDING : pending_tags_to_count[ tag ] } ) for tag in tags_to_do ]
|
||||
|
||||
|
||||
predicates = ClientSearch.SortPredicates( predicates, collapse_siblings = True )
|
||||
predicates = ClientSearch.SortPredicates( predicates, collapse_siblings = True )
|
||||
|
||||
self._next_updatelist_is_probably_fast = True
|
||||
|
||||
|
||||
matches = ClientSearch.FilterPredicates( search_text, predicates )
|
||||
|
||||
|
@ -1095,6 +1108,8 @@ class AutoCompleteDropdownTagsWrite( AutoCompleteDropdownTags ):
|
|||
|
||||
def _GenerateMatches( self ):
|
||||
|
||||
self._next_updatelist_is_probably_fast = False
|
||||
|
||||
num_autocomplete_chars = HC.options[ 'num_autocomplete_chars' ]
|
||||
|
||||
( search_text, entry_predicate, sibling_predicate ) = self._ParseSearchText()
|
||||
|
@ -1112,7 +1127,7 @@ class AutoCompleteDropdownTagsWrite( AutoCompleteDropdownTags ):
|
|||
|
||||
if ':' in search_text:
|
||||
|
||||
( namespace, other_half ) = search_text.split( ':' )
|
||||
( namespace, other_half ) = search_text.split( ':', 1 )
|
||||
|
||||
if other_half != '' and namespace != self._current_namespace:
|
||||
|
||||
|
@ -1129,6 +1144,8 @@ class AutoCompleteDropdownTagsWrite( AutoCompleteDropdownTags ):
|
|||
|
||||
predicates = HydrusGlobals.client_controller.Read( 'autocomplete_predicates', file_service_key = self._file_service_key, tag_service_key = self._tag_service_key, tag = search_text, add_namespaceless = False )
|
||||
|
||||
predicates = ClientSearch.SortPredicates( predicates, collapse_siblings = False )
|
||||
|
||||
else:
|
||||
|
||||
if must_do_a_search or self._cache_text == '' or not half_complete_tag.startswith( self._cache_text ):
|
||||
|
@ -1137,11 +1154,13 @@ class AutoCompleteDropdownTagsWrite( AutoCompleteDropdownTags ):
|
|||
|
||||
self._cached_results = HydrusGlobals.client_controller.Read( 'autocomplete_predicates', file_service_key = self._file_service_key, tag_service_key = self._tag_service_key, half_complete_tag = search_text, add_namespaceless = False )
|
||||
|
||||
self._cached_results = ClientSearch.SortPredicates( self._cached_results, collapse_siblings = False )
|
||||
|
||||
|
||||
predicates = self._cached_results
|
||||
|
||||
|
||||
predicates = ClientSearch.SortPredicates( predicates, collapse_siblings = False )
|
||||
self._next_updatelist_is_probably_fast = True
|
||||
|
||||
|
||||
matches = ClientSearch.FilterPredicates( half_complete_tag, predicates, service_key = self._tag_service_key, expand_parents = self._expand_parents )
|
||||
|
||||
|
@ -1598,9 +1617,7 @@ class ExportPatternButton( wx.Button ):
|
|||
|
||||
menu.Append( self.ID_TAG, 'a particular tag, if the file has it - (...)' )
|
||||
|
||||
self.PopupMenu( menu )
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
|
||||
class FitResistantStaticText( wx.StaticText ):
|
||||
|
@ -2432,31 +2449,34 @@ class ListBox( wx.ScrolledWindow ):
|
|||
|
||||
hit_index = None
|
||||
|
||||
if key_code in ( wx.WXK_HOME, wx.WXK_NUMPAD_HOME ):
|
||||
if len( self._ordered_strings ) > 0:
|
||||
|
||||
hit_index = 0
|
||||
|
||||
elif key_code in ( wx.WXK_END, wx.WXK_NUMPAD_END ):
|
||||
|
||||
hit_index = len( self._ordered_strings ) - 1
|
||||
|
||||
elif self._last_hit_index is not None:
|
||||
|
||||
if key_code in ( wx.WXK_UP, wx.WXK_NUMPAD_UP ):
|
||||
if key_code in ( wx.WXK_HOME, wx.WXK_NUMPAD_HOME ):
|
||||
|
||||
hit_index = self._last_hit_index - 1
|
||||
hit_index = 0
|
||||
|
||||
elif key_code in ( wx.WXK_DOWN, wx.WXK_NUMPAD_DOWN ):
|
||||
elif key_code in ( wx.WXK_END, wx.WXK_NUMPAD_END ):
|
||||
|
||||
hit_index = self._last_hit_index + 1
|
||||
hit_index = len( self._ordered_strings ) - 1
|
||||
|
||||
elif key_code in ( wx.WXK_PAGEUP, wx.WXK_NUMPAD_PAGEUP ):
|
||||
elif self._last_hit_index is not None:
|
||||
|
||||
hit_index = max( 0, self._last_hit_index - self._num_rows_per_page )
|
||||
|
||||
elif key_code in ( wx.WXK_PAGEDOWN, wx.WXK_NUMPAD_PAGEDOWN ):
|
||||
|
||||
hit_index = min( len( self._ordered_strings ) - 1, self._last_hit_index + self._num_rows_per_page )
|
||||
if key_code in ( wx.WXK_UP, wx.WXK_NUMPAD_UP ):
|
||||
|
||||
hit_index = self._last_hit_index - 1
|
||||
|
||||
elif key_code in ( wx.WXK_DOWN, wx.WXK_NUMPAD_DOWN ):
|
||||
|
||||
hit_index = self._last_hit_index + 1
|
||||
|
||||
elif key_code in ( wx.WXK_PAGEUP, wx.WXK_NUMPAD_PAGEUP ):
|
||||
|
||||
hit_index = max( 0, self._last_hit_index - self._num_rows_per_page )
|
||||
|
||||
elif key_code in ( wx.WXK_PAGEDOWN, wx.WXK_NUMPAD_PAGEDOWN ):
|
||||
|
||||
hit_index = min( len( self._ordered_strings ) - 1, self._last_hit_index + self._num_rows_per_page )
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -2596,6 +2616,8 @@ class ListBoxTags( ListBox ):
|
|||
|
||||
|
||||
|
||||
predicates = FlushOutPredicates( self, predicates )
|
||||
|
||||
if len( predicates ) > 0:
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'new_page_query', CC.LOCAL_FILE_SERVICE_KEY, initial_predicates = predicates )
|
||||
|
@ -2779,9 +2801,7 @@ class ListBoxTags( ListBox ):
|
|||
|
||||
|
||||
|
||||
self.PopupMenu( menu )
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
|
||||
event.Skip()
|
||||
|
@ -2807,11 +2827,13 @@ class ListBoxTagsAutocompleteDropdown( ListBoxTags ):
|
|||
|
||||
def _Activate( self ):
|
||||
|
||||
callable_terms = [ term for term in self._selected_terms if term.GetType() != HC.PREDICATE_TYPE_PARENT ]
|
||||
predicates = [ term for term in self._selected_terms if term.GetType() != HC.PREDICATE_TYPE_PARENT ]
|
||||
|
||||
if len( callable_terms ) > 0:
|
||||
predicates = FlushOutPredicates( self, predicates )
|
||||
|
||||
if len( predicates ) > 0:
|
||||
|
||||
self._callable( callable_terms )
|
||||
self._callable( predicates )
|
||||
|
||||
|
||||
|
||||
|
@ -2901,19 +2923,22 @@ class ListBoxTagsAutocompleteDropdown( ListBoxTags ):
|
|||
|
||||
hit_index = None
|
||||
|
||||
if key_code in ( wx.WXK_END, wx.WXK_NUMPAD_END ):
|
||||
if len( self._ordered_strings ) > 0:
|
||||
|
||||
hit_index = len( self._ordered_strings ) - 1
|
||||
|
||||
elif self._last_hit_index is not None:
|
||||
|
||||
if key_code in ( wx.WXK_DOWN, wx.WXK_NUMPAD_DOWN ):
|
||||
if key_code in ( wx.WXK_END, wx.WXK_NUMPAD_END ):
|
||||
|
||||
hit_index = self._last_hit_index + 1
|
||||
hit_index = len( self._ordered_strings ) - 1
|
||||
|
||||
elif key_code in ( wx.WXK_PAGEDOWN, wx.WXK_NUMPAD_PAGEDOWN ):
|
||||
elif self._last_hit_index is not None:
|
||||
|
||||
hit_index = min( len( self._ordered_strings ) - 1, self._last_hit_index + self._num_rows_per_page )
|
||||
if key_code in ( wx.WXK_DOWN, wx.WXK_NUMPAD_DOWN ):
|
||||
|
||||
hit_index = self._last_hit_index + 1
|
||||
|
||||
elif key_code in ( wx.WXK_PAGEDOWN, wx.WXK_NUMPAD_PAGEDOWN ):
|
||||
|
||||
hit_index = min( len( self._ordered_strings ) - 1, self._last_hit_index + self._num_rows_per_page )
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -3015,7 +3040,7 @@ class ListBoxTagsCensorship( ListBoxTags ):
|
|||
|
||||
for tag in tags:
|
||||
|
||||
self._RemoveTag( self._selected_terms )
|
||||
self._RemoveTag( tag )
|
||||
|
||||
|
||||
self._TextsHaveChanged()
|
||||
|
@ -5079,9 +5104,7 @@ class RegexButton( wx.Button ):
|
|||
|
||||
menu.AppendMenu( -1, 'favourites', submenu )
|
||||
|
||||
self.PopupMenu( menu )
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
|
||||
def EventMenu( self, event ):
|
||||
|
@ -5462,9 +5485,7 @@ class SeedCacheControl( SaneListCtrl ):
|
|||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'set_seed_skipped' ), 'skip' )
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'set_seed_unknown' ), 'try again' )
|
||||
|
||||
self.PopupMenu( menu )
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
|
||||
def NotifySeedAdded( self, seed ):
|
||||
|
|
|
@ -3813,7 +3813,7 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
|
|||
|
||||
if HC.options[ 'export_path' ] is not None:
|
||||
|
||||
abs_path = HydrusData.ConvertPortablePathToAbsPath( HC.options[ 'export_path' ] )
|
||||
abs_path = HydrusPaths.ConvertPortablePathToAbsPath( HC.options[ 'export_path' ] )
|
||||
|
||||
if abs_path is not None: self._export_location.SetPath( abs_path )
|
||||
|
||||
|
@ -4805,8 +4805,8 @@ class DialogManageRatings( ClientGUIDialogs.Dialog ):
|
|||
|
||||
#
|
||||
|
||||
like_services = HydrusGlobals.client_controller.GetServicesManager().GetServices( ( HC.LOCAL_RATING_LIKE, ) )
|
||||
numerical_services = HydrusGlobals.client_controller.GetServicesManager().GetServices( ( HC.LOCAL_RATING_NUMERICAL, ) )
|
||||
like_services = HydrusGlobals.client_controller.GetServicesManager().GetServices( ( HC.LOCAL_RATING_LIKE, ), randomised = False )
|
||||
numerical_services = HydrusGlobals.client_controller.GetServicesManager().GetServices( ( HC.LOCAL_RATING_NUMERICAL, ), randomised = False )
|
||||
|
||||
self._panels = []
|
||||
|
||||
|
|
|
@ -96,13 +96,18 @@ class FullscreenHoverFrame( wx.Frame ):
|
|||
in_x = my_ideal_x <= mouse_x and mouse_x <= my_ideal_x + my_ideal_width
|
||||
in_y = my_ideal_y <= mouse_y and mouse_y <= my_ideal_y + my_ideal_height
|
||||
|
||||
no_dialogs_open = True
|
||||
menu_open = HydrusGlobals.client_controller.MenuIsOpen()
|
||||
|
||||
dialog_open = False
|
||||
|
||||
tlps = wx.GetTopLevelWindows()
|
||||
|
||||
for tlp in tlps:
|
||||
|
||||
if isinstance( tlp, wx.Dialog ): no_dialogs_open = False
|
||||
if isinstance( tlp, wx.Dialog ):
|
||||
|
||||
dialog_open = True
|
||||
|
||||
|
||||
|
||||
mime = self._current_media.GetMime()
|
||||
|
@ -128,8 +133,8 @@ class FullscreenHoverFrame( wx.Frame ):
|
|||
tlp = tlp.GetParent()
|
||||
|
||||
|
||||
ready_to_show = in_position and not mouse_is_over_something_important and no_dialogs_open and my_parent_in_focus_tree
|
||||
ready_to_hide = not in_position or not no_dialogs_open or not my_parent_in_focus_tree
|
||||
ready_to_show = in_position and not mouse_is_over_something_important and my_parent_in_focus_tree and not dialog_open and not menu_open
|
||||
ready_to_hide = not menu_open and ( not in_position or dialog_open or not my_parent_in_focus_tree )
|
||||
|
||||
if ready_to_show:
|
||||
|
||||
|
@ -137,7 +142,10 @@ class FullscreenHoverFrame( wx.Frame ):
|
|||
|
||||
self.Show()
|
||||
|
||||
elif ready_to_hide: self.Hide()
|
||||
elif ready_to_hide:
|
||||
|
||||
self.Hide()
|
||||
|
||||
|
||||
|
||||
except wx.PyDeadObjectError:
|
||||
|
@ -493,7 +501,7 @@ class FullscreenHoverFrameRatings( FullscreenHoverFrame ):
|
|||
|
||||
like_hbox.AddF( ( 16, 16 ), CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
|
||||
like_services = HydrusGlobals.client_controller.GetServicesManager().GetServices( ( HC.LOCAL_RATING_LIKE, ) )
|
||||
like_services = HydrusGlobals.client_controller.GetServicesManager().GetServices( ( HC.LOCAL_RATING_LIKE, ), randomised = False )
|
||||
|
||||
for service in like_services:
|
||||
|
||||
|
@ -510,7 +518,7 @@ class FullscreenHoverFrameRatings( FullscreenHoverFrame ):
|
|||
vbox.AddF( self._file_repos, CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
vbox.AddF( like_hbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
|
||||
|
||||
numerical_services = HydrusGlobals.client_controller.GetServicesManager().GetServices( ( HC.LOCAL_RATING_NUMERICAL, ) )
|
||||
numerical_services = HydrusGlobals.client_controller.GetServicesManager().GetServices( ( HC.LOCAL_RATING_NUMERICAL, ), randomised = False )
|
||||
|
||||
for service in numerical_services:
|
||||
|
||||
|
|
|
@ -1879,7 +1879,10 @@ class MediaPanelThumbnails( MediaPanel ):
|
|||
|
||||
if len( self._sorted_media ) > 0:
|
||||
|
||||
if menu.GetMenuItemCount() > 0: menu.AppendSeparator()
|
||||
if menu.GetMenuItemCount() > 0:
|
||||
|
||||
menu.AppendSeparator()
|
||||
|
||||
|
||||
select_menu = wx.Menu()
|
||||
|
||||
|
@ -2201,10 +2204,10 @@ class MediaPanelThumbnails( MediaPanel ):
|
|||
|
||||
copy_menu = wx.Menu()
|
||||
|
||||
copy_menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'copy_files' ), copy_phrase )
|
||||
|
||||
if selection_has_local_file_service:
|
||||
|
||||
copy_menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'copy_files' ), copy_phrase )
|
||||
|
||||
copy_hash_menu = wx.Menu()
|
||||
|
||||
copy_hash_menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'copy_hash', 'sha256' ) , 'sha256 (hydrus default)' )
|
||||
|
@ -2309,9 +2312,7 @@ class MediaPanelThumbnails( MediaPanel ):
|
|||
|
||||
|
||||
|
||||
if menu.GetMenuItemCount() > 0: self.PopupMenu( menu )
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
event.Skip()
|
||||
|
||||
|
|
|
@ -268,9 +268,7 @@ class ConversationsListCtrl( wx.ListCtrl, ListCtrlAutoWidthMixin, ColumnSorterMi
|
|||
menu.AppendSeparator()
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'delete' ), 'delete' )
|
||||
|
||||
self.PopupMenu( menu )
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
|
||||
def GetListCtrl( self ): return self
|
||||
|
@ -641,9 +639,7 @@ class DestinationPanel( wx.Panel ):
|
|||
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'read' ), 'read' )
|
||||
|
||||
self.PopupMenu( menu )
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
|
||||
def EventRetryMenu( self, event ):
|
||||
|
@ -652,9 +648,7 @@ class DestinationPanel( wx.Panel ):
|
|||
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'retry' ), 'retry' )
|
||||
|
||||
self.PopupMenu( menu )
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
|
||||
def EventUnreadMenu( self, event ):
|
||||
|
@ -663,9 +657,7 @@ class DestinationPanel( wx.Panel ):
|
|||
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetTemporaryId( 'unread' ), 'unread' )
|
||||
|
||||
self.PopupMenu( menu )
|
||||
|
||||
wx.CallAfter( menu.Destroy )
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
|
||||
def SetStatus( self, status ):
|
||||
|
|
|
@ -19,12 +19,14 @@ import HydrusGlobals
|
|||
|
||||
class Page( wx.SplitterWindow ):
|
||||
|
||||
def __init__( self, parent, management_controller, initial_media_results ):
|
||||
def __init__( self, parent, controller, management_controller, initial_media_results ):
|
||||
|
||||
wx.SplitterWindow.__init__( self, parent )
|
||||
|
||||
self._page_key = HydrusData.GenerateKey()
|
||||
|
||||
self._controller = controller
|
||||
|
||||
self._management_controller = management_controller
|
||||
|
||||
self._management_controller.SetKey( 'page', self._page_key )
|
||||
|
@ -60,8 +62,8 @@ class Page( wx.SplitterWindow ):
|
|||
wx.CallAfter( self._search_preview_split.Unsplit, self._preview_panel )
|
||||
|
||||
|
||||
HydrusGlobals.client_controller.sub( self, 'SetPrettyStatus', 'new_page_status' )
|
||||
HydrusGlobals.client_controller.sub( self, 'SwapMediaPanel', 'swap_media_panel' )
|
||||
self._controller.sub( self, 'SetPrettyStatus', 'new_page_status' )
|
||||
self._controller.sub( self, 'SwapMediaPanel', 'swap_media_panel' )
|
||||
|
||||
|
||||
def CleanBeforeDestroy( self ): self._management_panel.CleanBeforeDestroy()
|
||||
|
@ -70,14 +72,14 @@ class Page( wx.SplitterWindow ):
|
|||
|
||||
self._search_preview_split.Unsplit( self._preview_panel )
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'set_focus', self._page_key, None )
|
||||
self._controller.pub( 'set_focus', self._page_key, None )
|
||||
|
||||
|
||||
def EventUnsplit( self, event ):
|
||||
|
||||
self.Unsplit( self._search_preview_split )
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'set_focus', self._page_key, None )
|
||||
self._controller.pub( 'set_focus', self._page_key, None )
|
||||
|
||||
|
||||
def GetManagementController( self ):
|
||||
|
@ -126,16 +128,25 @@ class Page( wx.SplitterWindow ):
|
|||
return ( x, y )
|
||||
|
||||
|
||||
def PageHidden( self ): HydrusGlobals.client_controller.pub( 'page_hidden', self._page_key )
|
||||
def PageHidden( self ):
|
||||
|
||||
self._controller.pub( 'page_hidden', self._page_key )
|
||||
|
||||
|
||||
def PageShown( self ): HydrusGlobals.client_controller.pub( 'page_shown', self._page_key )
|
||||
def PageShown( self ):
|
||||
|
||||
self._controller.pub( 'page_shown', self._page_key )
|
||||
|
||||
|
||||
def PrepareToHide( self ):
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'set_focus', self._page_key, None )
|
||||
self._controller.pub( 'set_focus', self._page_key, None )
|
||||
|
||||
|
||||
def RefreshQuery( self ): HydrusGlobals.client_controller.pub( 'refresh_query', self._page_key )
|
||||
def RefreshQuery( self ):
|
||||
|
||||
self._controller.pub( 'refresh_query', self._page_key )
|
||||
|
||||
|
||||
def ShowHideSplit( self ):
|
||||
|
||||
|
@ -143,7 +154,7 @@ class Page( wx.SplitterWindow ):
|
|||
|
||||
self.Unsplit( self._search_preview_split )
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'set_focus', self._page_key, None )
|
||||
self._controller.pub( 'set_focus', self._page_key, None )
|
||||
|
||||
else:
|
||||
|
||||
|
@ -161,13 +172,19 @@ class Page( wx.SplitterWindow ):
|
|||
|
||||
self._pretty_status = status
|
||||
|
||||
HydrusGlobals.client_controller.pub( 'refresh_status' )
|
||||
self._controller.pub( 'refresh_status' )
|
||||
|
||||
|
||||
|
||||
def SetSearchFocus( self ): HydrusGlobals.client_controller.pub( 'set_search_focus', self._page_key )
|
||||
def SetSearchFocus( self ):
|
||||
|
||||
self._controller.pub( 'set_search_focus', self._page_key )
|
||||
|
||||
|
||||
def SetSynchronisedWait( self ): HydrusGlobals.client_controller.pub( 'synchronised_wait_switch', self._page_key )
|
||||
def SetSynchronisedWait( self ):
|
||||
|
||||
self._controller.pub( 'synchronised_wait_switch', self._page_key )
|
||||
|
||||
|
||||
def SwapMediaPanel( self, page_key, new_panel ):
|
||||
|
||||
|
|
|
@ -187,14 +187,7 @@ class RasterContainerVideo( RasterContainer ):
|
|||
|
||||
else:
|
||||
|
||||
try:
|
||||
|
||||
self._frame_duration = ClientVideoHandling.GetVideoFrameDuration( self._path )
|
||||
|
||||
except HydrusExceptions.CantRenderWithCVException:
|
||||
|
||||
self._frame_duration = float( duration ) / num_frames
|
||||
|
||||
self._frame_duration = float( duration ) / num_frames
|
||||
|
||||
self._renderer = HydrusVideoHandling.VideoRendererFFMPEG( path, mime, duration, num_frames, target_resolution )
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ def GetVideoFrameDuration( path ):
|
|||
|
||||
fps = cv_video.get( CAP_PROP_FPS )
|
||||
|
||||
if fps == 0: raise HydrusExceptions.CantRenderWithCVException()
|
||||
if fps in ( 0, 1000 ): raise HydrusExceptions.CantRenderWithCVException()
|
||||
|
||||
return 1000.0 / fps
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ options = {}
|
|||
# Misc
|
||||
|
||||
NETWORK_VERSION = 17
|
||||
SOFTWARE_VERSION = 182
|
||||
SOFTWARE_VERSION = 183
|
||||
|
||||
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )
|
||||
|
||||
|
@ -291,7 +291,7 @@ NOISY_MIMES = tuple( [ APPLICATION_FLASH ] + list( AUDIO ) + list( VIDEO ) )
|
|||
|
||||
ARCHIVES = ( APPLICATION_ZIP, APPLICATION_HYDRUS_ENCRYPTED_ZIP )
|
||||
|
||||
MIMES_WITH_THUMBNAILS = ( IMAGE_JPEG, IMAGE_PNG, IMAGE_GIF, IMAGE_BMP, VIDEO_WEBM, VIDEO_FLV, VIDEO_MP4, VIDEO_WMV, VIDEO_MKV, VIDEO_WEBM )
|
||||
MIMES_WITH_THUMBNAILS = ( APPLICATION_FLASH, IMAGE_JPEG, IMAGE_PNG, IMAGE_GIF, IMAGE_BMP, VIDEO_FLV, VIDEO_MP4, VIDEO_WMV, VIDEO_MKV, VIDEO_WEBM )
|
||||
|
||||
# mp3 header is complicated
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import cProfile
|
||||
import cStringIO
|
||||
import HydrusConstants as HC
|
||||
import HydrusData
|
||||
import HydrusExceptions
|
||||
import HydrusGlobals
|
||||
import os
|
||||
import pstats
|
||||
import Queue
|
||||
import sqlite3
|
||||
import sys
|
||||
|
@ -266,11 +268,7 @@ class HydrusDB( object ):
|
|||
|
||||
HydrusData.ShowText( 'Profiling ' + job.GetType() + ' ' + job.GetAction() )
|
||||
|
||||
profile = cProfile.Profile()
|
||||
|
||||
profile.runctx( 'self._ProcessJob( job )', globals(), locals() )
|
||||
|
||||
profile.print_stats( sort = 'tottime' )
|
||||
HydrusData.Profile( 'self._ProcessJob( job )', globals(), locals() )
|
||||
|
||||
else:
|
||||
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import bs4
|
||||
import collections
|
||||
import cProfile
|
||||
import cStringIO
|
||||
import HydrusConstants as HC
|
||||
import HydrusExceptions
|
||||
import HydrusGlobals
|
||||
import HydrusSerialisable
|
||||
import locale
|
||||
import os
|
||||
import pstats
|
||||
import psutil
|
||||
import send2trash
|
||||
import shutil
|
||||
import sqlite3
|
||||
import subprocess
|
||||
|
@ -251,16 +253,6 @@ def ConvertPixelsToInt( unit ):
|
|||
elif unit == 'kilopixels': return 1000
|
||||
elif unit == 'megapixels': return 1000000
|
||||
|
||||
def ConvertPortablePathToAbsPath( portable_path ):
|
||||
|
||||
if portable_path is None: return None
|
||||
|
||||
if os.path.isabs( portable_path ): abs_path = portable_path
|
||||
else: abs_path = os.path.normpath( os.path.join( HC.BASE_DIR, portable_path ) )
|
||||
|
||||
if os.path.exists( abs_path ): return abs_path
|
||||
else: return None
|
||||
|
||||
def ConvertPrettyStringsToUglyNamespaces( pretty_strings ):
|
||||
|
||||
result = { s for s in pretty_strings if s != 'no namespace' }
|
||||
|
@ -570,20 +562,6 @@ def DebugPrint( debug_info ):
|
|||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
|
||||
def DeletePath( path ):
|
||||
|
||||
if os.path.exists( path ):
|
||||
|
||||
if os.path.isdir( path ):
|
||||
|
||||
shutil.rmtree( path )
|
||||
|
||||
else:
|
||||
|
||||
os.remove( path )
|
||||
|
||||
|
||||
|
||||
def DeserialisePrettyTags( text ):
|
||||
|
||||
text = text.replace( '\r', '' )
|
||||
|
@ -778,6 +756,42 @@ def Print( text ):
|
|||
|
||||
print( ToByteString( text ) )
|
||||
|
||||
def Profile( code, g, l ):
|
||||
|
||||
profile = cProfile.Profile()
|
||||
|
||||
profile.runctx( code, g, l )
|
||||
|
||||
output = cStringIO.StringIO()
|
||||
|
||||
stats = pstats.Stats( profile, stream = output )
|
||||
|
||||
stats.strip_dirs()
|
||||
|
||||
stats.sort_stats( 'tottime' )
|
||||
|
||||
output.seek( 0 )
|
||||
|
||||
output.write( 'Stats' )
|
||||
output.write( os.linesep )
|
||||
|
||||
stats.print_stats()
|
||||
|
||||
output.seek( 0 )
|
||||
|
||||
Print( output.read() )
|
||||
|
||||
output.seek( 0 )
|
||||
|
||||
output.write( 'Callers' )
|
||||
output.write( os.linesep )
|
||||
|
||||
stats.print_callers()
|
||||
|
||||
output.seek( 0 )
|
||||
|
||||
Print( output.read() )
|
||||
|
||||
def RecordRunningStart( instance ):
|
||||
|
||||
path = os.path.join( HC.BASE_DIR, instance + '_running' )
|
||||
|
@ -802,47 +816,6 @@ def RecordRunningStart( instance ):
|
|||
f.write( ToByteString( record_string ) )
|
||||
|
||||
|
||||
def RecyclePath( path ):
|
||||
|
||||
original_path = path
|
||||
|
||||
if HC.PLATFORM_LINUX:
|
||||
|
||||
# send2trash for Linux tries to do some Python3 str() stuff in prepping non-str paths for recycling
|
||||
|
||||
if not isinstance( path, str ):
|
||||
|
||||
try:
|
||||
|
||||
path = path.encode( sys.getfilesystemencoding() )
|
||||
|
||||
except:
|
||||
|
||||
Print( 'Trying to prepare a file for recycling created this error:' )
|
||||
traceback.print_exc()
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
if os.path.exists( path ):
|
||||
|
||||
try:
|
||||
|
||||
send2trash.send2trash( path )
|
||||
|
||||
except:
|
||||
|
||||
Print( 'Trying to recycle a file created this error:' )
|
||||
traceback.print_exc()
|
||||
|
||||
Print( 'It has been fully deleted instead.' )
|
||||
|
||||
DeletePath( original_path )
|
||||
|
||||
|
||||
|
||||
def ShowExceptionDefault( e ):
|
||||
|
||||
if isinstance( e, HydrusExceptions.ShutdownException ):
|
||||
|
|
|
@ -42,35 +42,63 @@ header_and_mime = [
|
|||
( 0, '\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C', HC.UNDETERMINED_WM )
|
||||
]
|
||||
|
||||
def SaveThumbnailToStream( pil_image, dimensions, f ):
|
||||
|
||||
HydrusImageHandling.EfficientlyThumbnailPILImage( pil_image, dimensions )
|
||||
|
||||
if pil_image.mode == 'P' and pil_image.info.has_key( 'transparency' ):
|
||||
|
||||
pil_image.save( f, 'PNG', transparency = pil_image.info[ 'transparency' ] )
|
||||
|
||||
elif pil_image.mode == 'RGBA':
|
||||
|
||||
pil_image.save( f, 'PNG' )
|
||||
|
||||
else:
|
||||
|
||||
pil_image = pil_image.convert( 'RGB' )
|
||||
|
||||
pil_image.save( f, 'JPEG', quality = 92 )
|
||||
|
||||
|
||||
def GenerateThumbnail( path, dimensions = HC.UNSCALED_THUMBNAIL_DIMENSIONS ):
|
||||
|
||||
mime = GetMime( path )
|
||||
|
||||
f = cStringIO.StringIO()
|
||||
|
||||
if mime in HC.IMAGES:
|
||||
|
||||
pil_image = HydrusImageHandling.GeneratePILImage( path )
|
||||
|
||||
HydrusImageHandling.EfficientlyThumbnailPILImage( pil_image, dimensions )
|
||||
SaveThumbnailToStream( pil_image, dimensions, f )
|
||||
|
||||
f = cStringIO.StringIO()
|
||||
elif mime == HC.APPLICATION_FLASH:
|
||||
|
||||
if pil_image.mode == 'P' and pil_image.info.has_key( 'transparency' ):
|
||||
|
||||
pil_image.save( f, 'PNG', transparency = pil_image.info[ 'transparency' ] )
|
||||
|
||||
elif pil_image.mode == 'RGBA': pil_image.save( f, 'PNG' )
|
||||
else:
|
||||
|
||||
pil_image = pil_image.convert( 'RGB' )
|
||||
|
||||
pil_image.save( f, 'JPEG', quality=92 )
|
||||
|
||||
( os_file_handle, temp_path ) = HydrusPaths.GetTempPath()
|
||||
|
||||
f.seek( 0 )
|
||||
|
||||
thumbnail = f.read()
|
||||
|
||||
f.close()
|
||||
try:
|
||||
|
||||
HydrusFlashHandling.RenderPageToFile( path, temp_path, 1 )
|
||||
|
||||
pil_image = HydrusImageHandling.GeneratePILImage( temp_path )
|
||||
|
||||
SaveThumbnailToStream( pil_image, dimensions, f )
|
||||
|
||||
except:
|
||||
|
||||
flash_default_path = os.path.join( HC.STATIC_DIR, 'flash.png' )
|
||||
|
||||
pil_image = HydrusImageHandling.GeneratePILImage( flash_default_path )
|
||||
|
||||
SaveThumbnailToStream( pil_image, dimensions, f )
|
||||
|
||||
finally:
|
||||
|
||||
del pil_image
|
||||
|
||||
HydrusPaths.CleanUpTempPath( os_file_handle, temp_path )
|
||||
|
||||
|
||||
else:
|
||||
|
||||
|
@ -84,17 +112,15 @@ def GenerateThumbnail( path, dimensions = HC.UNSCALED_THUMBNAIL_DIMENSIONS ):
|
|||
|
||||
pil_image = HydrusImageHandling.GeneratePILImageFromNumpyImage( numpy_image )
|
||||
|
||||
f = cStringIO.StringIO()
|
||||
|
||||
pil_image.save( f, 'JPEG', quality=92 )
|
||||
|
||||
f.seek( 0 )
|
||||
|
||||
thumbnail = f.read()
|
||||
|
||||
f.close()
|
||||
SaveThumbnailToStream( pil_image, dimensions, f )
|
||||
|
||||
|
||||
f.seek( 0 )
|
||||
|
||||
thumbnail = f.read()
|
||||
|
||||
f.close()
|
||||
|
||||
return thumbnail
|
||||
|
||||
def GetExtraHashesFromPath( path ):
|
||||
|
|
|
@ -1,7 +1,22 @@
|
|||
import hexagonitswfheader
|
||||
import HydrusConstants as HC
|
||||
import HydrusData
|
||||
import os
|
||||
import subprocess
|
||||
import traceback
|
||||
|
||||
if HC.PLATFORM_LINUX:
|
||||
|
||||
SWFRENDER_PATH = os.path.join( HC.BIN_DIR, 'swfrender_linux' )
|
||||
|
||||
elif HC.PLATFORM_OSX:
|
||||
|
||||
SWFRENDER_PATH = os.path.join( HC.BIN_DIR, 'swfrender_osx' )
|
||||
|
||||
elif HC.PLATFORM_WINDOWS:
|
||||
|
||||
SWFRENDER_PATH = os.path.join( HC.BIN_DIR, 'swfrender_win32.exe' )
|
||||
|
||||
# to all out there who write libraries:
|
||||
# hexagonit.swfheader is a perfect library. it is how you are supposed to do it.
|
||||
def GetFlashProperties( path ):
|
||||
|
@ -20,4 +35,14 @@ def GetFlashProperties( path ):
|
|||
|
||||
return ( ( width, height ), duration, num_frames )
|
||||
|
||||
|
||||
def RenderPageToFile( path, temp_path, page_index ):
|
||||
|
||||
cmd = [ SWFRENDER_PATH, path, '-o', temp_path, '-p', str( page_index ) ]
|
||||
|
||||
p = subprocess.Popen( cmd, startupinfo = HydrusData.GetSubprocessStartupInfo() )
|
||||
|
||||
p.wait()
|
||||
|
||||
p.communicate()
|
||||
|
|
@ -11,5 +11,6 @@ is_first_start = False
|
|||
is_db_updated = False
|
||||
|
||||
db_profile_mode = False
|
||||
pubsub_profile_mode = False
|
||||
special_debug_mode = False
|
||||
server_busy = False
|
||||
|
|
|
@ -65,7 +65,10 @@ def EfficientlyThumbnailPILImage( pil_image, ( target_x, target_y ) ):
|
|||
# if im_x > 2 * target_x or im_y > 2 * target_y: pil_image.thumbnail( ( 2 * target_x, 2 * target_y ), PILImage.NEAREST )
|
||||
#
|
||||
|
||||
pil_image.thumbnail( ( target_x, target_y ), PILImage.ANTIALIAS )
|
||||
if im_x > target_x or im_y > target_y:
|
||||
|
||||
pil_image.thumbnail( ( target_x, target_y ), PILImage.ANTIALIAS )
|
||||
|
||||
|
||||
def GeneratePILImage( path ):
|
||||
|
||||
|
|
|
@ -2,9 +2,13 @@ import gc
|
|||
import HydrusConstants as HC
|
||||
import HydrusData
|
||||
import os
|
||||
import send2trash
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import traceback
|
||||
|
||||
def CleanUpTempPath( os_file_handle, temp_path ):
|
||||
|
||||
|
@ -53,10 +57,34 @@ def ConvertAbsPathToPortablePath( abs_path ):
|
|||
try: return os.path.relpath( abs_path, HC.BASE_DIR )
|
||||
except: return abs_path
|
||||
|
||||
def ConvertPortablePathToAbsPath( portable_path ):
|
||||
|
||||
if portable_path is None: return None
|
||||
|
||||
if os.path.isabs( portable_path ): abs_path = portable_path
|
||||
else: abs_path = os.path.normpath( os.path.join( HC.BASE_DIR, portable_path ) )
|
||||
|
||||
if os.path.exists( abs_path ): return abs_path
|
||||
else: return None
|
||||
|
||||
def CopyFileLikeToFileLike( f_source, f_dest ):
|
||||
|
||||
for block in ReadFileLikeAsBlocks( f_source ): f_dest.write( block )
|
||||
|
||||
def DeletePath( path ):
|
||||
|
||||
if os.path.exists( path ):
|
||||
|
||||
if os.path.isdir( path ):
|
||||
|
||||
shutil.rmtree( path )
|
||||
|
||||
else:
|
||||
|
||||
os.remove( path )
|
||||
|
||||
|
||||
|
||||
def GetTempFile(): return tempfile.TemporaryFile()
|
||||
def GetTempFileQuick(): return tempfile.SpooledTemporaryFile( max_size = 1024 * 1024 * 4 )
|
||||
def GetTempPath(): return tempfile.mkstemp( prefix = 'hydrus' )
|
||||
|
@ -129,4 +157,45 @@ def ReadFileLikeAsBlocks( f ):
|
|||
|
||||
next_block = f.read( HC.READ_BLOCK_SIZE )
|
||||
|
||||
|
||||
def RecyclePath( path ):
|
||||
|
||||
original_path = path
|
||||
|
||||
if HC.PLATFORM_LINUX:
|
||||
|
||||
# send2trash for Linux tries to do some Python3 str() stuff in prepping non-str paths for recycling
|
||||
|
||||
if not isinstance( path, str ):
|
||||
|
||||
try:
|
||||
|
||||
path = path.encode( sys.getfilesystemencoding() )
|
||||
|
||||
except:
|
||||
|
||||
HydrusData.Print( 'Trying to prepare a file for recycling created this error:' )
|
||||
traceback.print_exc()
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
if os.path.exists( path ):
|
||||
|
||||
try:
|
||||
|
||||
send2trash.send2trash( path )
|
||||
|
||||
except:
|
||||
|
||||
HydrusData.Print( 'Trying to recycle a file created this error:' )
|
||||
traceback.print_exc()
|
||||
|
||||
HydrusData.Print( 'It has been fully deleted instead.' )
|
||||
|
||||
DeletePath( original_path )
|
||||
|
||||
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import HydrusConstants as HC
|
||||
import HydrusData
|
||||
import Queue
|
||||
import threading
|
||||
import traceback
|
||||
|
@ -103,7 +104,25 @@ class HydrusPubSub( object ):
|
|||
|
||||
for callable in callables:
|
||||
|
||||
callable( *args, **kwargs )
|
||||
if HydrusGlobals.pubsub_profile_mode:
|
||||
|
||||
text = 'Profiling ' + topic + ': ' + repr( callable )
|
||||
|
||||
if topic == 'message':
|
||||
|
||||
HydrusData.Print( text )
|
||||
|
||||
else:
|
||||
|
||||
HydrusData.ShowText( text )
|
||||
|
||||
|
||||
HydrusData.Profile( 'callable( *args, **kwargs )', globals(), locals() )
|
||||
|
||||
else:
|
||||
|
||||
callable( *args, **kwargs )
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ def ParseFileArguments( path ):
|
|||
if num_frames is not None: args[ 'num_frames' ] = num_frames
|
||||
if num_words is not None: args[ 'num_words' ] = num_words
|
||||
|
||||
if mime in HC.IMAGES:
|
||||
if mime in HC.MIMES_WITH_THUMBNAILS:
|
||||
|
||||
try: thumbnail = HydrusFileHandling.GenerateThumbnail( path )
|
||||
except: raise HydrusExceptions.ForbiddenException( 'Could not generate thumbnail from that file.' )
|
||||
|
@ -438,6 +438,11 @@ class HydrusResourceCommand( Resource ):
|
|||
|
||||
|
||||
|
||||
def _errbackDisconnected( self, failure, request_deferred ):
|
||||
|
||||
request_deferred.cancel()
|
||||
|
||||
|
||||
def _errbackHandleEmergencyError( self, failure, request ):
|
||||
|
||||
try: self._CleanUpTempFile( request )
|
||||
|
@ -449,7 +454,8 @@ class HydrusResourceCommand( Resource ):
|
|||
try: request.write( failure.getTraceback() )
|
||||
except: pass
|
||||
|
||||
request.finish()
|
||||
try: request.finish()
|
||||
except: pass
|
||||
|
||||
|
||||
def _errbackHandleProcessingError( self, failure, request ):
|
||||
|
@ -547,6 +553,8 @@ class HydrusResourceCommand( Resource ):
|
|||
|
||||
reactor.callLater( 0, d.callback, request )
|
||||
|
||||
request.notifyFinish().addErrback( self._errbackDisconnected, d )
|
||||
|
||||
return NOT_DONE_YET
|
||||
|
||||
|
||||
|
@ -570,6 +578,8 @@ class HydrusResourceCommand( Resource ):
|
|||
|
||||
reactor.callLater( 0, d.callback, request )
|
||||
|
||||
request.notifyFinish().addErrback( self._errbackDisconnected, d )
|
||||
|
||||
return NOT_DONE_YET
|
||||
|
||||
|
||||
|
|
|
@ -275,6 +275,7 @@ class VideoRendererFFMPEG( object ):
|
|||
else: self.depth = 3
|
||||
|
||||
( x, y ) = self._target_resolution
|
||||
|
||||
bufsize = self.depth * x * y
|
||||
|
||||
self.process = None
|
||||
|
|
|
@ -4,6 +4,7 @@ import httplib
|
|||
import HydrusConstants as HC
|
||||
import HydrusDB
|
||||
import HydrusExceptions
|
||||
import HydrusFileHandling
|
||||
import HydrusNATPunch
|
||||
import HydrusPaths
|
||||
import HydrusSerialisable
|
||||
|
@ -731,14 +732,14 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
path = ServerFiles.GetPath( 'file', hash )
|
||||
|
||||
HydrusData.RecyclePath( path )
|
||||
HydrusPaths.RecyclePath( path )
|
||||
|
||||
|
||||
for hash in thumbnails_hashes & deletee_hashes:
|
||||
|
||||
path = ServerFiles.GetPath( 'thumbnail', hash )
|
||||
|
||||
HydrusData.RecyclePath( path )
|
||||
HydrusPaths.RecyclePath( path )
|
||||
|
||||
|
||||
self._c.execute( 'DELETE FROM files_info WHERE hash_id IN ' + HydrusData.SplayListForDB( deletees ) + ';' )
|
||||
|
@ -1761,7 +1762,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
backup_path = os.path.join( HC.DB_DIR, 'server_backup' )
|
||||
|
||||
HydrusData.Print( 'backing up: deleting old backup' )
|
||||
HydrusData.RecyclePath( backup_path )
|
||||
HydrusPaths.RecyclePath( backup_path )
|
||||
|
||||
os.mkdir( backup_path )
|
||||
|
||||
|
@ -1938,7 +1939,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
if os.path.exists( update_dir ):
|
||||
|
||||
HydrusData.DeletePath( update_dir )
|
||||
HydrusPaths.DeletePath( update_dir )
|
||||
|
||||
|
||||
self.pub_after_commit( 'action_service', service_key, 'stop' )
|
||||
|
@ -2387,7 +2388,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
path = os.path.join( HC.SERVER_UPDATES_DIR, filename )
|
||||
|
||||
HydrusData.RecyclePath( path )
|
||||
HydrusPaths.RecyclePath( path )
|
||||
|
||||
|
||||
for ( service_id, end ) in first_ends:
|
||||
|
@ -2486,6 +2487,39 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
|
||||
|
||||
if version == 182:
|
||||
|
||||
HydrusData.Print( 'generating swf thumbnails' )
|
||||
|
||||
mimes = { HC.APPLICATION_FLASH }
|
||||
mimes.update( HC.VIDEO )
|
||||
|
||||
hash_ids = { hash_id for ( hash_id, ) in self._c.execute( 'SELECT hash_id FROM files_info WHERE mime IN ' + HydrusData.SplayListForDB( mimes ) + ';' ) }
|
||||
|
||||
for hash_id in hash_ids:
|
||||
|
||||
hash = self._GetHash( hash_id )
|
||||
|
||||
try:
|
||||
|
||||
file_path = ServerFiles.GetPath( 'file', hash )
|
||||
|
||||
except HydrusExceptions.NotFoundException:
|
||||
|
||||
continue
|
||||
|
||||
|
||||
thumbnail = HydrusFileHandling.GenerateThumbnail( file_path )
|
||||
|
||||
thumbnail_path = ServerFiles.GetExpectedPath( 'thumbnail', hash )
|
||||
|
||||
with open( thumbnail_path, 'wb' ) as f:
|
||||
|
||||
f.write( thumbnail )
|
||||
|
||||
|
||||
|
||||
|
||||
HydrusData.Print( 'The server has updated to version ' + str( version + 1 ) )
|
||||
|
||||
self._c.execute( 'UPDATE version SET version = ?;', ( version + 1, ) )
|
||||
|
|
|
@ -2,6 +2,7 @@ import ClientConstants as CC
|
|||
import ClientData
|
||||
import ClientGUIManagement
|
||||
import ClientGUIDialogsManage
|
||||
import ClientCaches
|
||||
import collections
|
||||
import HydrusConstants as HC
|
||||
import os
|
||||
|
@ -79,7 +80,7 @@ class TestManagers( unittest.TestCase ):
|
|||
|
||||
HydrusGlobals.test_controller.SetRead( 'services', services )
|
||||
|
||||
services_manager = ClientData.ServicesManager()
|
||||
services_manager = ClientCaches.ServicesManager( HydrusGlobals.client_controller )
|
||||
|
||||
#
|
||||
|
||||
|
@ -123,7 +124,7 @@ class TestManagers( unittest.TestCase ):
|
|||
command_1_inverted = { CC.LOCAL_FILE_SERVICE_KEY : [ HydrusData.ContentUpdate( HC.CONTENT_TYPE_FILES, HC.CONTENT_UPDATE_INBOX, { hash_1 } ) ] }
|
||||
command_2_inverted = { CC.LOCAL_FILE_SERVICE_KEY : [ HydrusData.ContentUpdate( HC.CONTENT_TYPE_FILES, HC.CONTENT_UPDATE_ARCHIVE, { hash_2 } ) ] }
|
||||
|
||||
undo_manager = ClientData.UndoManager()
|
||||
undo_manager = ClientCaches.UndoManager( HydrusGlobals.client_controller )
|
||||
|
||||
#
|
||||
|
||||
|
|
|
@ -580,7 +580,7 @@ class TestTagParents( unittest.TestCase ):
|
|||
|
||||
HydrusGlobals.test_controller.SetRead( 'tag_parents', tag_parents )
|
||||
|
||||
self._tag_parents_manager = ClientCaches.TagParentsManager()
|
||||
self._tag_parents_manager = ClientCaches.TagParentsManager( HydrusGlobals.client_controller )
|
||||
|
||||
|
||||
def test_expand_predicates( self ):
|
||||
|
@ -725,7 +725,7 @@ class TestTagSiblings( unittest.TestCase ):
|
|||
|
||||
HydrusGlobals.test_controller.SetRead( 'tag_siblings', tag_siblings )
|
||||
|
||||
self._tag_siblings_manager = ClientCaches.TagSiblingsManager()
|
||||
self._tag_siblings_manager = ClientCaches.TagSiblingsManager( HydrusGlobals.client_controller )
|
||||
|
||||
|
||||
def test_autocomplete( self ):
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
# This program is free software. It comes without any warranty, to
|
||||
# the extent permitted by applicable law. You can redistribute it
|
||||
# and/or modify it under the terms of the Do What The Fuck You Want
|
||||
|
|
16
test.py
16
test.py
|
@ -1,3 +1,5 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
import locale
|
||||
|
||||
try: locale.setlocale( locale.LC_ALL, '' )
|
||||
|
@ -87,17 +89,17 @@ class Controller( object ):
|
|||
|
||||
self._managers = {}
|
||||
|
||||
self._services_manager = ClientData.ServicesManager()
|
||||
self._services_manager = ClientCaches.ServicesManager( self )
|
||||
|
||||
self._managers[ 'hydrus_sessions' ] = ClientCaches.HydrusSessionManagerClient()
|
||||
self._managers[ 'tag_censorship' ] = ClientCaches.TagCensorshipManager()
|
||||
self._managers[ 'tag_siblings' ] = ClientCaches.TagSiblingsManager()
|
||||
self._managers[ 'tag_parents' ] = ClientCaches.TagParentsManager()
|
||||
self._managers[ 'undo' ] = ClientData.UndoManager()
|
||||
self._managers[ 'hydrus_sessions' ] = ClientCaches.HydrusSessionManager( self )
|
||||
self._managers[ 'tag_censorship' ] = ClientCaches.TagCensorshipManager( self )
|
||||
self._managers[ 'tag_siblings' ] = ClientCaches.TagSiblingsManager( self )
|
||||
self._managers[ 'tag_parents' ] = ClientCaches.TagParentsManager( self )
|
||||
self._managers[ 'undo' ] = ClientCaches.UndoManager( self )
|
||||
self._managers[ 'web_sessions' ] = TestConstants.FakeWebSessionManager()
|
||||
self._managers[ 'restricted_services_sessions' ] = HydrusSessions.HydrusSessionManagerServer()
|
||||
self._managers[ 'messaging_sessions' ] = HydrusSessions.HydrusMessagingSessionManagerServer()
|
||||
self._managers[ 'local_booru' ] = ClientCaches.LocalBooruCache()
|
||||
self._managers[ 'local_booru' ] = ClientCaches.LocalBooruCache( self )
|
||||
|
||||
self._cookies = {}
|
||||
|
||||
|
|
Loading…
Reference in New Issue