hydrus/include/ClientController.py

640 lines
24 KiB
Python
Raw Normal View History

2015-03-25 22:04:19 +00:00
import ClientCaches
2015-04-01 20:44:54 +00:00
import ClientData
2015-05-20 21:31:40 +00:00
import ClientDaemons
2013-11-06 18:22:07 +00:00
import hashlib
2013-09-25 20:20:10 +00:00
import httplib
2015-04-01 20:44:54 +00:00
import HydrusConstants as HC
import HydrusController
import HydrusData
2013-07-24 20:26:00 +00:00
import HydrusExceptions
2015-04-01 20:44:54 +00:00
import HydrusGlobals
2014-01-29 21:59:42 +00:00
import HydrusNetworking
2013-03-15 02:38:12 +00:00
import HydrusSessions
2013-09-25 20:20:10 +00:00
import HydrusServer
2013-07-17 20:56:13 +00:00
import HydrusTags
2014-05-21 21:37:35 +00:00
import HydrusThreading
2013-02-19 00:11:43 +00:00
import ClientConstants as CC
import ClientDB
import ClientGUI
2013-05-29 20:19:54 +00:00
import ClientGUIDialogs
2013-02-19 00:11:43 +00:00
import os
2013-08-28 21:31:52 +00:00
import random
2015-04-08 18:10:50 +00:00
import sqlite3
2014-01-08 18:40:02 +00:00
import subprocess
2013-07-24 20:26:00 +00:00
import sys
2015-04-08 18:10:50 +00:00
import threading
2013-02-19 00:11:43 +00:00
import time
import traceback
import wx
import wx.richtext
2013-10-02 22:06:06 +00:00
from twisted.internet import reactor
2013-10-23 21:36:47 +00:00
from twisted.internet import defer
2013-02-19 00:11:43 +00:00
ID_ANIMATED_EVENT_TIMER = wx.NewId()
ID_MAINTENANCE_EVENT_TIMER = wx.NewId()
2014-08-13 22:18:12 +00:00
MAINTENANCE_PERIOD = 5 * 60
2014-08-06 20:29:17 +00:00
2015-04-01 20:44:54 +00:00
class Controller( HydrusController.HydrusController ):
2014-12-03 22:56:40 +00:00
2015-04-01 20:44:54 +00:00
db_class = ClientDB.DB
2013-05-08 20:31:00 +00:00
2014-01-08 18:40:02 +00:00
def BackupDatabase( self ):
with wx.DirDialog( self._gui, 'Select backup location.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
2014-12-10 22:02:39 +00:00
text = 'Are you sure "' + path + '" is the correct directory?'
text += os.linesep * 2
text += 'Everything already in that directory will be deleted before the backup starts.'
text += os.linesep * 2
text += 'The database will be locked while the backup occurs, which may lock up your gui as well.'
2014-01-08 18:40:02 +00:00
2014-12-10 22:02:39 +00:00
with ClientGUIDialogs.DialogYesNo( self._gui, text ) as dlg_yn:
2014-01-08 18:40:02 +00:00
if dlg_yn.ShowModal() == wx.ID_YES:
self.Write( 'backup', path )
2014-09-03 20:26:49 +00:00
def Clipboard( self, data_type, data ):
2013-02-19 00:11:43 +00:00
# need this cause can't do it in a non-gui thread
2014-09-03 20:26:49 +00:00
if data_type == 'paths':
2013-02-19 00:11:43 +00:00
paths = data
if wx.TheClipboard.Open():
2013-03-15 02:38:12 +00:00
data = wx.DataObjectComposite()
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
file_data = wx.FileDataObject()
for path in paths: file_data.AddFile( path )
text_data = wx.TextDataObject( os.linesep.join( paths ) )
data.Add( file_data, True )
data.Add( text_data, False )
2013-02-19 00:11:43 +00:00
wx.TheClipboard.SetData( data )
wx.TheClipboard.Close()
2013-03-15 02:38:12 +00:00
else: wx.MessageBox( 'Could not get permission to access the clipboard!' )
2013-02-19 00:11:43 +00:00
2014-09-03 20:26:49 +00:00
elif data_type == 'text':
2013-03-23 17:57:29 +00:00
text = data
if wx.TheClipboard.Open():
data = wx.TextDataObject( text )
wx.TheClipboard.SetData( data )
wx.TheClipboard.Close()
else: wx.MessageBox( 'I could not get permission to access the clipboard.' )
2014-11-20 01:48:04 +00:00
elif data_type == 'bmp':
media = data
2015-04-01 20:44:54 +00:00
image_container = wx.GetApp().Cache( 'fullscreen' ).GetImage( media )
2014-11-20 01:48:04 +00:00
def THREADWait():
# have to do this in thread, because the image rendered needs the wx event queue to render
start_time = time.time()
while not image_container.IsRendered():
if time.time() - start_time > 15: raise Exception( 'The image did not render in fifteen seconds, so the attempt to copy it to the clipboard was abandoned.' )
time.sleep( 0.1 )
wx.CallAfter( CopyToClipboard )
def CopyToClipboard():
if wx.TheClipboard.Open():
hydrus_bmp = image_container.GetHydrusBitmap()
wx_bmp = hydrus_bmp.GetWxBitmap()
data = wx.BitmapDataObject( wx_bmp )
wx.TheClipboard.SetData( data )
wx.TheClipboard.Close()
else: wx.MessageBox( 'I could not get permission to access the clipboard.' )
HydrusThreading.CallToThread( THREADWait )
2013-02-19 00:11:43 +00:00
2014-12-03 22:56:40 +00:00
def CurrentlyIdle( self ):
2015-05-13 20:22:39 +00:00
if self._options[ 'idle_period' ] == 0: return False
2014-12-03 22:56:40 +00:00
2015-05-13 20:22:39 +00:00
return HydrusData.GetNow() - self._timestamps[ 'last_user_action' ] > self._options[ 'idle_period' ]
2014-12-03 22:56:40 +00:00
2014-02-19 22:37:23 +00:00
2015-04-01 20:44:54 +00:00
def DoHTTP( self, *args, **kwargs ): return self._http.Request( *args, **kwargs )
2013-02-19 00:11:43 +00:00
2015-06-03 21:05:13 +00:00
def ForceIdle( self ):
self._timestamps[ 'last_user_action' ] = 0
HydrusGlobals.pubsub.pub( 'refresh_status' )
2013-02-19 00:11:43 +00:00
def GetGUI( self ): return self._gui
2014-09-03 20:26:49 +00:00
def GetManager( self, manager_type ): return self._managers[ manager_type ]
2013-10-09 18:13:42 +00:00
2015-05-13 20:22:39 +00:00
def GetOptions( self ):
return self._options
2014-08-06 20:29:17 +00:00
def InitCheckPassword( self ):
while True:
with wx.PasswordEntryDialog( None, 'Enter your password', 'Enter password' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
2015-05-13 20:22:39 +00:00
if hashlib.sha256( dlg.GetValue() ).digest() == self._options[ 'password' ]: break
2014-08-06 20:29:17 +00:00
else: raise HydrusExceptions.PermissionException()
def InitDB( self ):
db_initialised = False
while not db_initialised:
try:
2015-04-01 20:44:54 +00:00
HydrusController.HydrusController.InitDB( self )
2014-08-06 20:29:17 +00:00
db_initialised = True
except HydrusExceptions.DBAccessException as e:
2015-03-25 22:04:19 +00:00
try: print( HydrusData.ToString( e ) )
except: print( repr( HydrusData.ToString( e ) ) )
2014-08-06 20:29:17 +00:00
2015-04-08 18:10:50 +00:00
def wx_code():
message = 'This instance of the client had a problem connecting to the database, which probably means an old instance is still closing.'
message += os.linesep * 2
message += 'If the old instance does not close for a _very_ long time, you can usually safely force-close it from task manager.'
2014-08-06 20:29:17 +00:00
2015-04-08 18:10:50 +00:00
with ClientGUIDialogs.DialogYesNo( None, message, 'There was a problem connecting to the database.', yes_label = 'wait a bit, then try again', no_label = 'forget it' ) as dlg:
if dlg.ShowModal() == wx.ID_YES: time.sleep( 3 )
else: raise HydrusExceptions.PermissionException()
2014-08-06 20:29:17 +00:00
2015-04-08 18:10:50 +00:00
HydrusThreading.CallBlockingToWx( wx_code )
2014-08-06 20:29:17 +00:00
def InitGUI( self ):
self._managers = {}
2015-03-18 21:46:29 +00:00
self._managers[ 'services' ] = ClientData.ServicesManager()
2014-08-13 22:18:12 +00:00
2014-08-06 20:29:17 +00:00
self._managers[ 'hydrus_sessions' ] = HydrusSessions.HydrusSessionManagerClient()
2015-03-18 21:46:29 +00:00
self._managers[ 'local_booru' ] = ClientCaches.LocalBooruCache()
2014-08-06 20:29:17 +00:00
self._managers[ 'tag_censorship' ] = HydrusTags.TagCensorshipManager()
self._managers[ 'tag_siblings' ] = HydrusTags.TagSiblingsManager()
self._managers[ 'tag_parents' ] = HydrusTags.TagParentsManager()
2015-03-18 21:46:29 +00:00
self._managers[ 'undo' ] = ClientData.UndoManager()
2014-08-06 20:29:17 +00:00
self._managers[ 'web_sessions' ] = HydrusSessions.WebSessionManagerClient()
2015-04-01 20:44:54 +00:00
self._caches[ 'fullscreen' ] = ClientCaches.RenderedImageCache( 'fullscreen' )
self._caches[ 'preview' ] = ClientCaches.RenderedImageCache( 'preview' )
self._caches[ 'thumbnail' ] = ClientCaches.ThumbnailCache()
2014-08-06 20:29:17 +00:00
2015-06-10 19:40:25 +00:00
if HC.options[ 'proxy' ] is not None:
( proxytype, host, port, username, password ) = HC.options[ 'proxy' ]
HydrusNetworking.SetProxy( proxytype, host, port, username, password )
2014-08-06 20:29:17 +00:00
CC.GlobalBMPs.STATICInitialise()
self._gui = ClientGUI.FrameGUI()
2015-03-25 22:04:19 +00:00
HydrusGlobals.pubsub.sub( self, 'Clipboard', 'clipboard' )
HydrusGlobals.pubsub.sub( self, 'RestartServer', 'restart_server' )
HydrusGlobals.pubsub.sub( self, 'RestartBooru', 'restart_booru' )
2014-08-06 20:29:17 +00:00
# this is because of some bug in wx C++ that doesn't add these by default
wx.richtext.RichTextBuffer.AddHandler( wx.richtext.RichTextHTMLHandler() )
wx.richtext.RichTextBuffer.AddHandler( wx.richtext.RichTextXMLHandler() )
2015-03-25 22:04:19 +00:00
if HydrusGlobals.is_first_start: wx.CallAfter( self._gui.DoFirstStart )
if HydrusGlobals.is_db_updated: wx.CallLater( 1, HydrusData.ShowText, 'The client has updated to version ' + HydrusData.ToString( HC.SOFTWARE_VERSION ) + '!' )
2014-08-06 20:29:17 +00:00
self.RestartServer()
self.RestartBooru()
2015-05-20 21:31:40 +00:00
self.StartDaemons()
2014-08-06 20:29:17 +00:00
2015-06-03 21:05:13 +00:00
self.ResetIdleTimer()
2014-08-06 20:29:17 +00:00
2013-02-19 00:11:43 +00:00
def MaintainDB( self ):
2015-03-25 22:04:19 +00:00
now = HydrusData.GetNow()
2013-02-19 00:11:43 +00:00
shutdown_timestamps = self.Read( 'shutdown_timestamps' )
2015-05-13 20:22:39 +00:00
if self._options[ 'maintenance_vacuum_period' ] != 0:
2014-12-03 22:56:40 +00:00
2015-05-13 20:22:39 +00:00
if now - shutdown_timestamps[ CC.SHUTDOWN_TIMESTAMP_VACUUM ] > self._options[ 'maintenance_vacuum_period' ]: self.Write( 'vacuum' )
2014-12-03 22:56:40 +00:00
2015-05-13 20:22:39 +00:00
if self._options[ 'maintenance_delete_orphans_period' ] != 0:
2014-12-03 22:56:40 +00:00
2015-05-13 20:22:39 +00:00
if now - shutdown_timestamps[ CC.SHUTDOWN_TIMESTAMP_DELETE_ORPHANS ] > self._options[ 'maintenance_delete_orphans_period' ]: self.Write( 'delete_orphans' )
2014-12-03 22:56:40 +00:00
2013-02-19 00:11:43 +00:00
2015-04-08 18:10:50 +00:00
if self._timestamps[ 'last_service_info_cache_fatten' ] != 0 and now - self._timestamps[ 'last_service_info_cache_fatten' ] > 60 * 20:
2014-08-06 20:29:17 +00:00
2015-04-08 18:10:50 +00:00
HydrusGlobals.pubsub.pub( 'splash_set_text', 'fattening service info' )
2014-04-23 20:56:12 +00:00
2014-08-13 22:18:12 +00:00
services = self.GetManager( 'services' ).GetServices()
2014-04-23 20:56:12 +00:00
2014-12-17 22:35:12 +00:00
for service in services:
try: self.Read( 'service_info', service.GetServiceKey() )
except: pass # sometimes this breaks when a service has just been removed and the client is closing, so ignore the error
2014-04-23 20:56:12 +00:00
2015-03-25 22:04:19 +00:00
self._timestamps[ 'last_service_info_cache_fatten' ] = HydrusData.GetNow()
2014-08-06 20:29:17 +00:00
2015-03-25 22:04:19 +00:00
HydrusGlobals.pubsub.pub( 'clear_closed_pages' )
2014-04-23 20:56:12 +00:00
2013-02-19 00:11:43 +00:00
def OnInit( self ):
2014-10-29 21:39:01 +00:00
2015-04-01 20:44:54 +00:00
HydrusController.HydrusController.OnInit( self )
2014-10-29 21:39:01 +00:00
2013-09-25 20:20:10 +00:00
self._local_service = None
2014-07-09 22:15:14 +00:00
self._booru_service = None
2013-09-25 20:20:10 +00:00
2015-04-01 20:44:54 +00:00
self._http = HydrusNetworking.HTTPConnectionManager()
2013-11-06 18:22:07 +00:00
2013-02-19 00:11:43 +00:00
try:
2015-04-08 18:10:50 +00:00
splash = ClientGUI.FrameSplash()
2013-02-19 00:11:43 +00:00
except:
2014-08-06 20:29:17 +00:00
print( 'There was an error trying to start the splash screen!' )
2013-02-19 00:11:43 +00:00
2014-08-06 20:29:17 +00:00
print( traceback.format_exc() )
2013-02-19 00:11:43 +00:00
2014-08-06 20:29:17 +00:00
try: wx.CallAfter( splash.Destroy )
2014-01-22 21:11:22 +00:00
except: pass
2014-08-06 20:29:17 +00:00
return False
2013-02-19 00:11:43 +00:00
2015-04-08 18:10:50 +00:00
boot_thread = threading.Thread( target = self.THREADBootEverything, name = 'Application Boot Thread' )
wx.CallAfter( boot_thread.start )
return True
2013-02-19 00:11:43 +00:00
def PrepStringForDisplay( self, text ):
2015-05-13 20:22:39 +00:00
if self._options[ 'gui_capitalisation' ]: return text
2013-02-19 00:11:43 +00:00
else: return text.lower()
2015-03-25 22:04:19 +00:00
def ResetIdleTimer( self ): self._timestamps[ 'last_user_action' ] = HydrusData.GetNow()
2014-08-13 22:18:12 +00:00
2014-07-09 22:15:14 +00:00
def RestartBooru( self ):
2015-03-25 22:04:19 +00:00
service = self.GetManager( 'services' ).GetService( CC.LOCAL_BOORU_SERVICE_KEY )
2014-07-09 22:15:14 +00:00
info = service.GetInfo()
port = info[ 'port' ]
def TWISTEDRestartServer():
def StartServer( *args, **kwargs ):
try:
try:
2015-06-10 19:40:25 +00:00
connection = HydrusNetworking.GetLocalConnection( port )
2014-07-09 22:15:14 +00:00
connection.close()
2015-03-25 22:04:19 +00:00
text = 'The client\'s booru server could not start because something was already bound to port ' + HydrusData.ToString( port ) + '.'
2014-07-09 22:15:14 +00:00
text += os.linesep * 2
text += 'This usually means another hydrus client is already running and occupying that port. It could be a previous instantiation of this client that has yet to shut itself down.'
text += os.linesep * 2
text += 'You can change the port this client tries to host its local server on in services->manage services.'
2015-03-25 22:04:19 +00:00
wx.CallLater( 1, HydrusData.ShowText, text )
2014-07-09 22:15:14 +00:00
except:
2015-03-25 22:04:19 +00:00
self._booru_service = reactor.listenTCP( port, HydrusServer.HydrusServiceBooru( CC.LOCAL_BOORU_SERVICE_KEY, HC.LOCAL_BOORU, 'This is the local booru.' ) )
2014-07-09 22:15:14 +00:00
try:
2015-06-10 19:40:25 +00:00
connection = HydrusNetworking.GetLocalConnection( port )
2014-07-09 22:15:14 +00:00
connection.close()
2015-06-10 19:40:25 +00:00
except Exception as e:
2014-07-09 22:15:14 +00:00
2015-06-10 19:40:25 +00:00
text = 'Tried to bind port ' + HydrusData.ToString( port ) + ' for the local booru, but it failed:'
text += os.linesep * 2
text += HydrusData.ToString( e )
2014-07-09 22:15:14 +00:00
2015-03-25 22:04:19 +00:00
wx.CallLater( 1, HydrusData.ShowText, text )
2014-07-09 22:15:14 +00:00
2015-06-03 21:05:13 +00:00
except Exception as e:
wx.CallAfter( HydrusData.ShowException, e )
2014-07-09 22:15:14 +00:00
if self._booru_service is None: StartServer()
else:
deferred = defer.maybeDeferred( self._booru_service.stopListening )
deferred.addCallback( StartServer )
reactor.callFromThread( TWISTEDRestartServer )
2013-09-25 20:20:10 +00:00
def RestartServer( self ):
2015-05-13 20:22:39 +00:00
port = self._options[ 'local_port' ]
2013-09-25 20:20:10 +00:00
def TWISTEDRestartServer():
2013-10-23 21:36:47 +00:00
def StartServer( *args, **kwargs ):
2013-09-25 20:20:10 +00:00
try:
2013-10-02 22:06:06 +00:00
try:
2015-06-10 19:40:25 +00:00
connection = HydrusNetworking.GetLocalConnection( port )
2013-10-02 22:06:06 +00:00
connection.close()
2015-03-25 22:04:19 +00:00
text = 'The client\'s local server could not start because something was already bound to port ' + HydrusData.ToString( port ) + '.'
2014-05-28 21:03:24 +00:00
text += os.linesep * 2
text += 'This usually means another hydrus client is already running and occupying that port. It could be a previous instantiation of this client that has yet to shut itself down.'
text += os.linesep * 2
text += 'You can change the port this client tries to host its local server on in file->options.'
2013-10-02 22:06:06 +00:00
2015-03-25 22:04:19 +00:00
wx.CallLater( 1, HydrusData.ShowText, text )
2013-10-02 22:06:06 +00:00
except:
2015-03-25 22:04:19 +00:00
self._local_service = reactor.listenTCP( port, HydrusServer.HydrusServiceLocal( CC.LOCAL_FILE_SERVICE_KEY, HC.LOCAL_FILE, 'This is the local file service.' ) )
2013-10-02 22:06:06 +00:00
try:
2015-06-10 19:40:25 +00:00
connection = HydrusNetworking.GetLocalConnection( port )
2013-10-02 22:06:06 +00:00
connection.close()
2015-06-10 19:40:25 +00:00
except Exception as e:
2013-10-02 22:06:06 +00:00
2015-06-10 19:40:25 +00:00
text = 'Tried to bind port ' + HydrusData.ToString( port ) + ' for the local server, but it failed:'
text += os.linesep * 2
text += HydrusData.ToString( e )
2013-10-02 22:06:06 +00:00
2015-03-25 22:04:19 +00:00
wx.CallLater( 1, HydrusData.ShowText, text )
2013-10-02 22:06:06 +00:00
2015-06-03 21:05:13 +00:00
except Exception as e:
wx.CallAfter( HydrusData.ShowException, e )
2013-09-25 20:20:10 +00:00
if self._local_service is None: StartServer()
else:
2013-10-23 21:36:47 +00:00
deferred = defer.maybeDeferred( self._local_service.stopListening )
2013-09-25 20:20:10 +00:00
2013-10-23 21:36:47 +00:00
deferred.addCallback( StartServer )
2013-09-25 20:20:10 +00:00
2013-10-02 22:06:06 +00:00
reactor.callFromThread( TWISTEDRestartServer )
2013-09-25 20:20:10 +00:00
2014-01-08 18:40:02 +00:00
def RestoreDatabase( self ):
with wx.DirDialog( self._gui, 'Select backup location.' ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
2014-12-10 22:02:39 +00:00
text = 'Are you sure you want to restore a backup from "' + path + '"?'
text += os.linesep * 2
text += 'Everything in your current database will be deleted!'
text += os.linesep * 2
text += 'The gui will shut down, and then it will take a while to complete the restore. Once it is done, the client will restart.'
2014-01-08 18:40:02 +00:00
2014-12-10 22:02:39 +00:00
with ClientGUIDialogs.DialogYesNo( self._gui, text ) as dlg_yn:
2014-01-08 18:40:02 +00:00
if dlg_yn.ShowModal() == wx.ID_YES:
self._gui.Hide()
2014-01-22 21:11:22 +00:00
self._gui.Close()
2014-01-08 18:40:02 +00:00
self._db.Shutdown()
2014-08-06 20:29:17 +00:00
while not self._db.LoopIsFinished(): time.sleep( 0.1 )
2014-01-08 18:40:02 +00:00
self._db.RestoreBackup( path )
call_stuff = [ sys.executable ]
call_stuff.extend( sys.argv )
2015-01-07 23:09:00 +00:00
subprocess.Popen( call_stuff, shell = True )
2014-01-08 18:40:02 +00:00
2014-05-21 21:37:35 +00:00
def StartFileQuery( self, query_key, search_context ): HydrusThreading.CallToThread( self.THREADDoFileQuery, query_key, search_context )
2013-08-28 21:31:52 +00:00
2015-05-20 21:31:40 +00:00
def StartDaemons( self ):
HydrusThreading.DAEMONWorker( 'CheckImportFolders', ClientDaemons.DAEMONCheckImportFolders, ( 'notify_restart_import_folders_daemon', 'notify_new_import_folders' ), period = 180 )
HydrusThreading.DAEMONWorker( 'CheckExportFolders', ClientDaemons.DAEMONCheckExportFolders, ( 'notify_restart_export_folders_daemon', 'notify_new_export_folders' ), period = 180 )
HydrusThreading.DAEMONWorker( 'DownloadFiles', ClientDaemons.DAEMONDownloadFiles, ( 'notify_new_downloads', 'notify_new_permissions' ) )
HydrusThreading.DAEMONWorker( 'ResizeThumbnails', ClientDaemons.DAEMONResizeThumbnails, period = 3600 * 24, init_wait = 600 )
HydrusThreading.DAEMONWorker( 'SynchroniseAccounts', ClientDaemons.DAEMONSynchroniseAccounts, ( 'permissions_are_stale', ) )
HydrusThreading.DAEMONWorker( 'SynchroniseRepositories', ClientDaemons.DAEMONSynchroniseRepositories, ( 'notify_restart_repo_sync_daemon', 'notify_new_permissions' ) )
HydrusThreading.DAEMONWorker( 'SynchroniseSubscriptions', ClientDaemons.DAEMONSynchroniseSubscriptions, ( 'notify_restart_subs_sync_daemon', 'notify_new_subscriptions' ), period = 360, init_wait = 120 )
HydrusThreading.DAEMONWorker( 'UPnP', ClientDaemons.DAEMONUPnP, ( 'notify_new_upnp_mappings', ), pre_callable_wait = 10 )
HydrusThreading.DAEMONQueue( 'FlushRepositoryUpdates', ClientDaemons.DAEMONFlushServiceUpdates, 'service_updates_delayed', period = 5 )
2013-08-28 21:31:52 +00:00
def THREADDoFileQuery( self, query_key, search_context ):
2015-03-04 22:44:32 +00:00
query_hash_ids = self.Read( 'file_query_ids', search_context )
query_hash_ids = list( query_hash_ids )
random.shuffle( query_hash_ids )
limit = search_context.GetSystemPredicates().GetLimit()
if limit is not None: query_hash_ids = query_hash_ids[ : limit ]
service_key = search_context.GetFileServiceKey()
media_results = []
2015-04-22 22:57:25 +00:00
for sub_query_hash_ids in HydrusData.SplitListIntoChunks( query_hash_ids, 256 ):
2013-08-28 21:31:52 +00:00
2015-03-04 22:44:32 +00:00
if query_key.IsCancelled(): return
2013-08-28 21:31:52 +00:00
2015-03-04 22:44:32 +00:00
more_media_results = self.Read( 'media_results_from_ids', service_key, sub_query_hash_ids )
2013-08-28 21:31:52 +00:00
2015-03-04 22:44:32 +00:00
media_results.extend( more_media_results )
2013-08-28 21:31:52 +00:00
2015-03-25 22:04:19 +00:00
HydrusGlobals.pubsub.pub( 'set_num_query_results', len( media_results ), len( query_hash_ids ) )
2013-08-28 21:31:52 +00:00
2015-04-01 20:44:54 +00:00
self.WaitUntilWXThreadIdle()
2013-08-28 21:31:52 +00:00
2015-03-04 22:44:32 +00:00
2015-03-25 22:04:19 +00:00
HydrusGlobals.pubsub.pub( 'file_query_done', query_key, media_results )
2013-08-28 21:31:52 +00:00
2015-04-08 18:10:50 +00:00
def THREADBootEverything( self ):
try:
HydrusGlobals.pubsub.pub( 'splash_set_text', 'booting db' )
self.InitDB() # can't run on wx thread because we need event queue free to update splash text
2015-05-13 20:22:39 +00:00
self._options = wx.GetApp().Read( 'options' )
HC.options = self._options
2015-04-29 19:20:35 +00:00
2015-05-13 20:22:39 +00:00
if self._options[ 'password' ] is not None:
2015-04-08 18:10:50 +00:00
HydrusGlobals.pubsub.pub( 'splash_set_text', 'waiting for password' )
HydrusThreading.CallBlockingToWx( self.InitCheckPassword )
HydrusGlobals.pubsub.pub( 'splash_set_text', 'booting gui' )
HydrusThreading.CallBlockingToWx( self.InitGUI )
except HydrusExceptions.PermissionException as e: pass
except:
2015-04-22 22:57:25 +00:00
traceback.print_exc()
2015-04-08 18:10:50 +00:00
text = 'A serious error occured while trying to start the program. Its traceback has been written to client.log.'
print( text )
wx.CallAfter( wx.MessageBox, text )
finally:
HydrusGlobals.pubsub.pub( 'splash_destroy' )
def THREADExitEverything( self ):
2015-06-03 21:05:13 +00:00
2015-04-08 18:10:50 +00:00
HydrusGlobals.pubsub.pub( 'splash_set_text', 'exiting gui' )
gui = self.GetGUI()
try: HydrusThreading.CallBlockingToWx( gui.TestAbleToClose )
except: return
try:
HydrusThreading.CallBlockingToWx( gui.Shutdown )
HydrusGlobals.pubsub.pub( 'splash_set_text', 'exiting db' )
HydrusThreading.CallBlockingToWx( self.MaintainDB )
self.ShutdownDB() # can't run on wx thread because we need event queue free to update splash text
except HydrusExceptions.PermissionException as e: pass
except:
2015-04-22 22:57:25 +00:00
traceback.print_exc()
2015-04-08 18:10:50 +00:00
text = 'A serious error occured while trying to exit the program. Its traceback has been written to client.log. You may need to quit the program from task manager.'
print( text )
wx.CallAfter( wx.MessageBox, text )
finally:
HydrusGlobals.pubsub.pub( 'splash_destroy' )
2013-02-19 00:11:43 +00:00
def Write( self, action, *args, **kwargs ):
2013-12-04 22:44:16 +00:00
if action == 'content_updates': self._managers[ 'undo' ].AddCommand( 'content_updates', *args, **kwargs )
2013-07-10 20:25:57 +00:00
2015-04-01 20:44:54 +00:00
return HydrusController.HydrusController.Write( self, action, *args, **kwargs )
2013-07-31 21:26:38 +00:00
2013-02-19 00:11:43 +00:00