Version 172
This commit is contained in:
parent
a61df3303c
commit
91b77e6648
11
client.pyw
11
client.pyw
|
@ -21,6 +21,9 @@ try:
|
|||
import threading
|
||||
from twisted.internet import reactor
|
||||
from include import HydrusGlobals
|
||||
import traceback
|
||||
|
||||
HydrusGlobals.instance = HC.HYDRUS_CLIENT
|
||||
|
||||
initial_sys_stdout = sys.stdout
|
||||
initial_sys_stderr = sys.stderr
|
||||
|
@ -36,15 +39,14 @@ try:
|
|||
|
||||
threading.Thread( target = reactor.run, kwargs = { 'installSignalHandlers' : 0 } ).start()
|
||||
|
||||
app = ClientController.Controller()
|
||||
controller = ClientController.Controller()
|
||||
|
||||
app.MainLoop()
|
||||
controller.Run()
|
||||
|
||||
except:
|
||||
|
||||
print( 'hydrus client failed at ' + time.ctime() )
|
||||
|
||||
import traceback
|
||||
print( traceback.format_exc() )
|
||||
|
||||
finally:
|
||||
|
@ -52,7 +54,8 @@ try:
|
|||
HydrusGlobals.view_shutdown = True
|
||||
HydrusGlobals.model_shutdown = True
|
||||
|
||||
app.pubimmediate( 'shutdown' )
|
||||
try: controller.pubimmediate( 'wake_daemons' )
|
||||
except: pass
|
||||
|
||||
reactor.callFromThread( reactor.stop )
|
||||
|
||||
|
|
|
@ -8,6 +8,39 @@
|
|||
<div class="content">
|
||||
<h3>changelog</h3>
|
||||
<ul>
|
||||
<li><h3>version 172</h3></li>
|
||||
<ul>
|
||||
<li>the server no longer needs wx!</li>
|
||||
<li>the server now runs from command line</li>
|
||||
<li>the server is now .py, not .pyw!</li>
|
||||
<li>run 'server help' for more info</li>
|
||||
<li>improved how the controllers start</li>
|
||||
<li>improved how the controllers stop</li>
|
||||
<li>improved controller boot error handling</li>
|
||||
<li>improved how pages close</li>
|
||||
<li>general controller code cleanup</li>
|
||||
<li>general server code cleanup</li>
|
||||
<li>fixed the always_on_shutdown (without asking) option, which was asking anyway</li>
|
||||
<li>removed a debug statement in isalreadyrunning code, whoops!</li>
|
||||
<li>improved isalreadyrunning detection. it should work breddy gud now</li>
|
||||
<li>added gallery file limit to new 'downloading' options page, which folds in the old thread checker options as well</li>
|
||||
<li>added option to always embed the autocomplete dropdown window (rather than having it a floating window), which is now default on for Linux and OS X</li>
|
||||
<li>manage services now supports two kinds of service reset for repositories</li>
|
||||
<li>the service reset buttons now only fire on dialog ok</li>
|
||||
<li>service reset will try, as cpu allows, to update its progress in a message popup window</li>
|
||||
<li>administrators now have a 'sync now' button on the review services window that lets you catch up immediately to the service without having to wait for the normal update time (this will burn cpu time serverside, so be careful!)</li>
|
||||
<li>fixed a bug when searching boorus with unicode-16 characters</li>
|
||||
<li>the client updates directory is neater</li>
|
||||
<li>'system busy' status is now shown on the status bar</li>
|
||||
<li>'force unbusy' added to debug menu</li>
|
||||
<li>invalid characters in export filenames will now be replaced by underscores</li>
|
||||
<li>fixed a bug where rating services' cached file counts were not decrementing on de-ratings</li>
|
||||
<li>rating services' cached file counts are reset on update</li>
|
||||
<li>hover windows will pop in over video again, but will not if the mouse is _near_ the animation bar</li>
|
||||
<li>searching for ':' in the autocomplete dropdown will no longer search the db for every single tag jej</li>
|
||||
<li>improved some server_busy logic</li>
|
||||
<li>improved some server shutdown logic</li>
|
||||
</ul>
|
||||
<li><h3>version 171</h3></li>
|
||||
<ul>
|
||||
<li>improved isalreadyrunning code</li>
|
||||
|
|
|
@ -28,20 +28,18 @@ import threading
|
|||
import time
|
||||
import traceback
|
||||
import wx
|
||||
import wx.richtext
|
||||
from twisted.internet import reactor
|
||||
from twisted.internet import defer
|
||||
|
||||
ID_ANIMATED_EVENT_TIMER = wx.NewId()
|
||||
ID_MAINTENANCE_EVENT_TIMER = wx.NewId()
|
||||
|
||||
MAINTENANCE_PERIOD = 5 * 60
|
||||
|
||||
class Controller( HydrusController.HydrusController ):
|
||||
|
||||
db_class = ClientDB.DB
|
||||
pubsub_binding_errors_to_ignore = [ wx.PyDeadObjectError ]
|
||||
|
||||
def _InitDB( self ):
|
||||
|
||||
return ClientDB.DB( self )
|
||||
|
||||
|
||||
def BackupDatabase( self ):
|
||||
|
||||
with wx.DirDialog( self._gui, 'Select backup location.' ) as dlg:
|
||||
|
@ -79,11 +77,11 @@ class Controller( HydrusController.HydrusController ):
|
|||
|
||||
except Exception as e:
|
||||
|
||||
print( 'CallBlockingToWx just caught this error:' )
|
||||
print( traceback.format_exc() )
|
||||
|
||||
job_key.SetVariable( 'error', e )
|
||||
|
||||
print( 'CallBlockingToWx just caught this error:' )
|
||||
HydrusData.DebugPrint( traceback.format_exc() )
|
||||
|
||||
finally: job_key.Finish()
|
||||
|
||||
|
||||
|
@ -104,6 +102,43 @@ class Controller( HydrusController.HydrusController ):
|
|||
else: raise job_key.GetVariable( 'error' )
|
||||
|
||||
|
||||
def CheckAlreadyRunning( self ):
|
||||
|
||||
while HydrusData.IsAlreadyRunning( 'client' ):
|
||||
|
||||
self.pub( 'splash_set_text', 'client already running' )
|
||||
|
||||
def wx_code():
|
||||
|
||||
message = 'It looks like another instance of this client is already running, so this instance cannot start.'
|
||||
message += os.linesep * 2
|
||||
message += 'If the old instance is closing and does not quit for a _very_ long time, it is usually safe to force-close it from task manager.'
|
||||
|
||||
with ClientGUIDialogs.DialogYesNo( self._splash, message, 'The client is already running.', yes_label = 'wait a bit, then try again', no_label = 'forget it' ) as dlg:
|
||||
|
||||
if dlg.ShowModal() != wx.ID_YES:
|
||||
|
||||
raise HydrusExceptions.PermissionException()
|
||||
|
||||
|
||||
|
||||
|
||||
self.CallBlockingToWx( wx_code )
|
||||
|
||||
for i in range( 10, 0, -1 ):
|
||||
|
||||
if not HydrusData.IsAlreadyRunning( 'client' ):
|
||||
|
||||
break
|
||||
|
||||
|
||||
self.pub( 'splash_set_text', 'waiting ' + str( i ) + ' seconds' )
|
||||
|
||||
time.sleep( 1 )
|
||||
|
||||
|
||||
|
||||
|
||||
def Clipboard( self, data_type, data ):
|
||||
|
||||
# need this cause can't do it in a non-gui thread
|
||||
|
@ -224,25 +259,29 @@ class Controller( HydrusController.HydrusController ):
|
|||
|
||||
def Exit( self ):
|
||||
|
||||
try: self._splash = ClientGUI.FrameSplash()
|
||||
try:
|
||||
|
||||
self._gui.TestAbleToClose()
|
||||
|
||||
except HydrusExceptions.PermissionException:
|
||||
|
||||
return
|
||||
|
||||
|
||||
try:
|
||||
|
||||
self._splash = ClientGUI.FrameSplash()
|
||||
|
||||
except Exception as e:
|
||||
|
||||
print( 'There was an error trying to start the splash screen!' )
|
||||
|
||||
print( traceback.format_exc() )
|
||||
|
||||
try:
|
||||
|
||||
wx.CallAfter( self._splash.Destroy )
|
||||
|
||||
except: pass
|
||||
|
||||
raise e
|
||||
|
||||
|
||||
exit_thread = threading.Thread( target = self.THREADExitEverything, name = 'Application Exit Thread' )
|
||||
|
||||
wx.CallAfter( exit_thread.start )
|
||||
exit_thread.start()
|
||||
|
||||
|
||||
def ForceIdle( self ):
|
||||
|
@ -253,9 +292,17 @@ class Controller( HydrusController.HydrusController ):
|
|||
self.pub( 'refresh_status' )
|
||||
|
||||
|
||||
def GetGUI( self ): return self._gui
|
||||
def ForceUnbusy( self ):
|
||||
|
||||
self._system_busy = False
|
||||
|
||||
self.pub( 'wake_daemons' )
|
||||
self.pub( 'refresh_status' )
|
||||
|
||||
|
||||
def GetManager( self, manager_type ): return self._managers[ manager_type ]
|
||||
def GetDB( self ): return self._db
|
||||
|
||||
def GetGUI( self ): return self._gui
|
||||
|
||||
def GetOptions( self ):
|
||||
|
||||
|
@ -267,24 +314,97 @@ class Controller( HydrusController.HydrusController ):
|
|||
return self._services_manager
|
||||
|
||||
|
||||
def InitCheckPassword( self ):
|
||||
def InitModel( self ):
|
||||
|
||||
while True:
|
||||
self.pub( 'splash_set_text', 'booting db' )
|
||||
|
||||
self._http = HydrusNetworking.HTTPConnectionManager()
|
||||
|
||||
HydrusController.HydrusController.InitModel( self )
|
||||
|
||||
self._options = self.Read( 'options' )
|
||||
|
||||
HC.options = self._options
|
||||
|
||||
self._services_manager = ClientData.ServicesManager()
|
||||
|
||||
self._managers[ 'hydrus_sessions' ] = HydrusSessions.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' ] = HydrusSessions.WebSessionManagerClient()
|
||||
|
||||
if HC.options[ 'proxy' ] is not None:
|
||||
|
||||
with wx.PasswordEntryDialog( self._splash, 'Enter your password', 'Enter password' ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
|
||||
if hashlib.sha256( dlg.GetValue() ).digest() == self._options[ 'password' ]: break
|
||||
|
||||
else: raise HydrusExceptions.PermissionException()
|
||||
|
||||
( proxytype, host, port, username, password ) = HC.options[ 'proxy' ]
|
||||
|
||||
HydrusNetworking.SetProxy( proxytype, host, port, username, password )
|
||||
|
||||
|
||||
def wx_code():
|
||||
|
||||
self._caches[ 'fullscreen' ] = ClientCaches.RenderedImageCache( 'fullscreen' )
|
||||
self._caches[ 'preview' ] = ClientCaches.RenderedImageCache( 'preview' )
|
||||
self._caches[ 'thumbnail' ] = ClientCaches.ThumbnailCache()
|
||||
|
||||
CC.GlobalBMPs.STATICInitialise()
|
||||
|
||||
|
||||
self.CallBlockingToWx( wx_code )
|
||||
|
||||
self.sub( self, 'Clipboard', 'clipboard' )
|
||||
self.sub( self, 'RestartServer', 'restart_server' )
|
||||
self.sub( self, 'RestartBooru', 'restart_booru' )
|
||||
|
||||
|
||||
def InitDaemons( self ):
|
||||
def InitView( self ):
|
||||
|
||||
HydrusController.HydrusController.InitDaemons( self )
|
||||
if self._options[ 'password' ] is not None:
|
||||
|
||||
self.pub( 'splash_set_text', 'waiting for password' )
|
||||
|
||||
def wx_code_password():
|
||||
|
||||
while True:
|
||||
|
||||
with wx.PasswordEntryDialog( self._splash, 'Enter your password', 'Enter password' ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
|
||||
if hashlib.sha256( dlg.GetValue() ).digest() == self._options[ 'password' ]: break
|
||||
|
||||
else: raise HydrusExceptions.PermissionException( 'Bad password check' )
|
||||
|
||||
|
||||
|
||||
|
||||
self.CallBlockingToWx( wx_code_password )
|
||||
|
||||
|
||||
self.pub( 'splash_set_text', 'booting gui' )
|
||||
|
||||
def wx_code_gui():
|
||||
|
||||
self._gui = ClientGUI.FrameGUI()
|
||||
|
||||
# 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() )
|
||||
|
||||
self.ResetIdleTimer()
|
||||
|
||||
|
||||
self.CallBlockingToWx( wx_code_gui )
|
||||
|
||||
HydrusController.HydrusController.InitView( self )
|
||||
|
||||
self._local_service = None
|
||||
self._booru_service = None
|
||||
|
||||
self.RestartServer()
|
||||
self.RestartBooru()
|
||||
|
||||
self._daemons.append( HydrusThreading.DAEMONWorker( self, 'CheckImportFolders', ClientDaemons.DAEMONCheckImportFolders, ( 'notify_restart_import_folders_daemon', 'notify_new_import_folders' ), period = 180 ) )
|
||||
self._daemons.append( HydrusThreading.DAEMONWorker( self, 'CheckExportFolders', ClientDaemons.DAEMONCheckExportFolders, ( 'notify_restart_export_folders_daemon', 'notify_new_export_folders' ), period = 180 ) )
|
||||
|
@ -297,53 +417,9 @@ class Controller( HydrusController.HydrusController ):
|
|||
|
||||
self._daemons.append( HydrusThreading.DAEMONQueue( self, 'FlushRepositoryUpdates', ClientDaemons.DAEMONFlushServiceUpdates, 'service_updates_delayed', period = 5 ) )
|
||||
|
||||
|
||||
def InitGUI( self ):
|
||||
|
||||
self._managers = {}
|
||||
|
||||
self._services_manager = ClientData.ServicesManager()
|
||||
|
||||
self._managers[ 'hydrus_sessions' ] = HydrusSessions.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' ] = HydrusSessions.WebSessionManagerClient()
|
||||
|
||||
self._caches[ 'fullscreen' ] = ClientCaches.RenderedImageCache( 'fullscreen' )
|
||||
self._caches[ 'preview' ] = ClientCaches.RenderedImageCache( 'preview' )
|
||||
self._caches[ 'thumbnail' ] = ClientCaches.ThumbnailCache()
|
||||
|
||||
if HC.options[ 'proxy' ] is not None:
|
||||
|
||||
( proxytype, host, port, username, password ) = HC.options[ 'proxy' ]
|
||||
|
||||
HydrusNetworking.SetProxy( proxytype, host, port, username, password )
|
||||
|
||||
|
||||
CC.GlobalBMPs.STATICInitialise()
|
||||
|
||||
self._gui = ClientGUI.FrameGUI()
|
||||
|
||||
self.sub( self, 'Clipboard', 'clipboard' )
|
||||
self.sub( self, 'RestartServer', 'restart_server' )
|
||||
self.sub( self, 'RestartBooru', 'restart_booru' )
|
||||
|
||||
# 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() )
|
||||
|
||||
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 ) + '!' )
|
||||
|
||||
self.RestartServer()
|
||||
self.RestartBooru()
|
||||
self.InitDaemons()
|
||||
|
||||
self.ResetIdleTimer()
|
||||
|
||||
|
||||
def MaintainDB( self ):
|
||||
|
||||
|
@ -399,38 +475,6 @@ class Controller( HydrusController.HydrusController ):
|
|||
wx.CallAfter( self.ProcessPubSub )
|
||||
|
||||
|
||||
def OnInit( self ):
|
||||
|
||||
self.InitData()
|
||||
|
||||
self._local_service = None
|
||||
self._booru_service = None
|
||||
|
||||
self._http = HydrusNetworking.HTTPConnectionManager()
|
||||
|
||||
try:
|
||||
|
||||
self._splash = ClientGUI.FrameSplash()
|
||||
|
||||
except:
|
||||
|
||||
print( 'There was an error trying to start the splash screen!' )
|
||||
|
||||
print( traceback.format_exc() )
|
||||
|
||||
try: wx.CallAfter( self._splash.Destroy )
|
||||
except: pass
|
||||
|
||||
return False
|
||||
|
||||
|
||||
boot_thread = threading.Thread( target = self.THREADBootEverything, name = 'Application Boot Thread' )
|
||||
|
||||
wx.CallAfter( boot_thread.start )
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def PrepStringForDisplay( self, text ):
|
||||
|
||||
if self._options[ 'gui_capitalisation' ]: return text
|
||||
|
@ -603,7 +647,7 @@ class Controller( HydrusController.HydrusController ):
|
|||
|
||||
restart_thread = threading.Thread( target = THREADRestart, name = 'Application Restart Thread' )
|
||||
|
||||
wx.CallAfter( restart_thread.start )
|
||||
restart_thread.start()
|
||||
|
||||
|
||||
|
||||
|
@ -611,6 +655,99 @@ class Controller( HydrusController.HydrusController ):
|
|||
|
||||
|
||||
|
||||
def Run( self ):
|
||||
|
||||
self._app = wx.App()
|
||||
|
||||
self._app.SetAssertMode( wx.PYAPP_ASSERT_SUPPRESS )
|
||||
|
||||
try:
|
||||
|
||||
self._splash = ClientGUI.FrameSplash()
|
||||
|
||||
except:
|
||||
|
||||
print( 'There was an error trying to start the splash screen!' )
|
||||
|
||||
print( traceback.format_exc() )
|
||||
|
||||
raise
|
||||
|
||||
|
||||
self.pub( 'splash_set_text', 'initialising' )
|
||||
|
||||
boot_thread = threading.Thread( target = self.THREADBootEverything, name = 'Application Boot Thread' )
|
||||
|
||||
boot_thread.start()
|
||||
|
||||
self._app.MainLoop()
|
||||
|
||||
|
||||
def ShutdownModel( self ):
|
||||
|
||||
self.pub( 'splash_set_text', 'exiting db' )
|
||||
|
||||
HydrusController.HydrusController.ShutdownModel( self )
|
||||
|
||||
|
||||
def ShutdownView( self ):
|
||||
|
||||
self.pub( 'splash_set_text', 'exiting gui' )
|
||||
|
||||
self.CallBlockingToWx( self._gui.Shutdown )
|
||||
|
||||
self.pub( 'splash_set_text', 'waiting for daemons to exit' )
|
||||
|
||||
HydrusController.HydrusController.ShutdownView( self )
|
||||
|
||||
idle_shutdown_action = self._options[ 'idle_shutdown' ]
|
||||
|
||||
if idle_shutdown_action in ( CC.IDLE_ON_SHUTDOWN, CC.IDLE_ON_SHUTDOWN_ASK_FIRST ):
|
||||
|
||||
# callblockingtowx needs view_shutdown to be true for the job_key to not quit early lol! fix this!
|
||||
|
||||
HydrusGlobals.view_shutdown = False
|
||||
|
||||
self.pub( 'splash_set_text', 'running maintenance' )
|
||||
|
||||
self.ResetIdleTimer()
|
||||
|
||||
do_it = True
|
||||
|
||||
if CC.IDLE_ON_SHUTDOWN_ASK_FIRST:
|
||||
|
||||
if self.ThereIsIdleShutdownWorkDue():
|
||||
|
||||
def wx_code():
|
||||
|
||||
text = 'Is now a good time for the client to do up to ' + HydrusData.ConvertIntToPrettyString( self._options[ 'idle_shutdown_max_minutes' ] ) + ' minutes\' maintenance work?'
|
||||
|
||||
with ClientGUIDialogs.DialogYesNo( self._splash, text, title = 'Maintenance is due' ) as dlg_yn:
|
||||
|
||||
if dlg_yn.ShowModal() == wx.ID_YES:
|
||||
|
||||
return True
|
||||
|
||||
else:
|
||||
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
do_it = self.CallBlockingToWx( wx_code )
|
||||
|
||||
|
||||
|
||||
if do_it:
|
||||
|
||||
self.DoIdleShutdownWork()
|
||||
|
||||
|
||||
HydrusGlobals.view_shutdown = True
|
||||
|
||||
|
||||
|
||||
def StartFileQuery( self, query_key, search_context ):
|
||||
|
||||
self.CallToThread( self.THREADDoFileQuery, query_key, search_context )
|
||||
|
@ -707,67 +844,25 @@ class Controller( HydrusController.HydrusController ):
|
|||
|
||||
try:
|
||||
|
||||
while HydrusData.IsAlreadyRunning():
|
||||
|
||||
self.pub( 'splash_set_text', 'client already running' )
|
||||
|
||||
def wx_code():
|
||||
|
||||
message = 'It looks like another instance of this client is already running, so this instance cannot start.'
|
||||
message += os.linesep * 2
|
||||
message += 'If the old instance is closing and does not quit for a _very_ long time, it is usually safe to force-close it from task manager.'
|
||||
|
||||
with ClientGUIDialogs.DialogYesNo( self._splash, message, 'The client is already running.', yes_label = 'wait a bit, then try again', no_label = 'forget it' ) as dlg:
|
||||
|
||||
if dlg.ShowModal() != wx.ID_YES:
|
||||
|
||||
raise HydrusExceptions.PermissionException()
|
||||
|
||||
|
||||
|
||||
|
||||
self.CallBlockingToWx( wx_code )
|
||||
|
||||
for i in range( 10, 0, -1 ):
|
||||
|
||||
if not HydrusData.IsAlreadyRunning():
|
||||
|
||||
break
|
||||
|
||||
|
||||
self.pub( 'splash_set_text', 'waiting ' + str( i ) + ' seconds' )
|
||||
|
||||
time.sleep( 1 )
|
||||
|
||||
|
||||
self.CheckAlreadyRunning()
|
||||
|
||||
self.pub( 'splash_set_text', 'booting db' )
|
||||
HydrusData.RecordRunningStart( 'client' )
|
||||
|
||||
self.InitDB() # can't run on wx thread because we need event queue free to update splash text
|
||||
self.InitModel()
|
||||
|
||||
self._options = self.Read( 'options' )
|
||||
self.InitView()
|
||||
|
||||
HC.options = self._options
|
||||
except HydrusExceptions.PermissionException as e:
|
||||
|
||||
if self._options[ 'password' ] is not None:
|
||||
|
||||
self.pub( 'splash_set_text', 'waiting for password' )
|
||||
|
||||
self.CallBlockingToWx( self.InitCheckPassword )
|
||||
|
||||
print( e )
|
||||
|
||||
self.pub( 'splash_set_text', 'booting gui' )
|
||||
|
||||
self.CallBlockingToWx( self.InitGUI )
|
||||
|
||||
except HydrusExceptions.PermissionException as e: pass
|
||||
except:
|
||||
|
||||
traceback.print_exc()
|
||||
|
||||
text = 'A serious error occured while trying to start the program. Its traceback will be shown next. It should have also been written to client.log.'
|
||||
|
||||
print( text )
|
||||
traceback.print_exc()
|
||||
|
||||
HydrusData.DebugPrint( text )
|
||||
|
||||
wx.CallAfter( wx.MessageBox, text )
|
||||
wx.CallAfter( wx.MessageBox, traceback.format_exc() )
|
||||
|
@ -780,70 +875,11 @@ class Controller( HydrusController.HydrusController ):
|
|||
|
||||
def THREADExitEverything( self ):
|
||||
|
||||
self.pub( 'splash_set_text', 'exiting gui' )
|
||||
|
||||
try: self.CallBlockingToWx( self._gui.TestAbleToClose )
|
||||
except:
|
||||
|
||||
self.pub( 'splash_destroy' )
|
||||
|
||||
return
|
||||
|
||||
|
||||
try:
|
||||
|
||||
self.CallBlockingToWx( self._gui.Shutdown )
|
||||
self.ShutdownView()
|
||||
|
||||
HydrusGlobals.view_shutdown = True
|
||||
|
||||
self.pub( 'wake_daemons' )
|
||||
|
||||
self.pub( 'splash_set_text', 'waiting for daemons to exit' )
|
||||
|
||||
while True in ( daemon.is_alive() for daemon in self._daemons ):
|
||||
|
||||
time.sleep( 0.1 )
|
||||
|
||||
|
||||
idle_shutdown_action = self._options[ 'idle_shutdown' ]
|
||||
|
||||
if idle_shutdown_action in ( CC.IDLE_ON_SHUTDOWN, CC.IDLE_ON_SHUTDOWN_ASK_FIRST ):
|
||||
|
||||
self.ResetIdleTimer()
|
||||
|
||||
self.pub( 'splash_set_text', 'running maintenance' )
|
||||
|
||||
do_it = True
|
||||
|
||||
if True and CC.IDLE_ON_SHUTDOWN_ASK_FIRST:
|
||||
|
||||
if self.ThereIsIdleShutdownWorkDue():
|
||||
|
||||
text = 'Is now a good time for the client to do up to ' + HydrusData.ConvertIntToPrettyString( self._options[ 'idle_shutdown_max_minutes' ] ) + ' minutes\' maintenance work?'
|
||||
|
||||
with ClientGUIDialogs.DialogYesNo( self._splash, text, title = 'Maintenance is due' ) as dlg_yn:
|
||||
|
||||
if dlg_yn.ShowModal() != wx.ID_YES:
|
||||
|
||||
do_it = False
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if do_it:
|
||||
|
||||
HydrusGlobals.view_shutdown = False
|
||||
|
||||
self.DoIdleShutdownWork()
|
||||
|
||||
HydrusGlobals.view_shutdown = True
|
||||
|
||||
|
||||
|
||||
self.pub( 'splash_set_text', 'exiting db' )
|
||||
|
||||
self.ShutdownDB() # can't run on wx thread because we need event queue free to update splash text
|
||||
self.ShutdownModel()
|
||||
|
||||
except HydrusExceptions.PermissionException as e: pass
|
||||
except:
|
||||
|
@ -852,7 +888,7 @@ class Controller( HydrusController.HydrusController ):
|
|||
|
||||
text = 'A serious error occured while trying to exit the program. Its traceback will be shown next. It should have also been written to client.log. You may need to quit the program from task manager.'
|
||||
|
||||
print( text )
|
||||
HydrusData.DebugPrint( text )
|
||||
|
||||
wx.CallAfter( wx.MessageBox, text )
|
||||
|
||||
|
|
|
@ -1112,6 +1112,13 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
if service_type in HC.REPOSITORIES:
|
||||
|
||||
update_dir = ClientFiles.GetExpectedUpdateDir( service_key )
|
||||
|
||||
if not os.path.exists( update_dir ):
|
||||
|
||||
os.mkdir( update_dir )
|
||||
|
||||
|
||||
if 'first_timestamp' not in info: info[ 'first_timestamp' ] = None
|
||||
if 'next_download_timestamp' not in info: info[ 'next_download_timestamp' ] = 0
|
||||
if 'next_processing_timestamp' not in info: info[ 'next_processing_timestamp' ] = 0
|
||||
|
@ -4629,7 +4636,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self._c.execute( 'DELETE FROM local_ratings WHERE service_id = ? AND hash_id IN ' + splayed_hash_ids + ';', ( service_id, ) )
|
||||
|
||||
rowcount = self._GetRowCount()
|
||||
ratings_added -= self._GetRowCount()
|
||||
|
||||
if rating is not None:
|
||||
|
||||
|
@ -4876,7 +4883,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
self._c.execute( 'DELETE FROM autocomplete_tags_cache WHERE tag_service_id = ?;', ( self._combined_tag_service_id, ) )
|
||||
|
||||
|
||||
def _ResetService( self, service_key ):
|
||||
def _ResetService( self, service_key, delete_updates = False ):
|
||||
|
||||
service_id = self._GetServiceId( service_key )
|
||||
|
||||
|
@ -4884,26 +4891,59 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
( service_key, service_type, name, info ) = service.ToTuple()
|
||||
|
||||
prefix = 'resetting ' + name
|
||||
|
||||
job_key = HydrusData.JobKey()
|
||||
|
||||
job_key.SetVariable( 'popup_text_1', prefix + ': deleting from main service table' )
|
||||
|
||||
self._controller.pub( 'message', job_key )
|
||||
|
||||
self._c.execute( 'DELETE FROM services WHERE service_id = ?;', ( service_id, ) )
|
||||
|
||||
if service_id in self._service_cache: del self._service_cache[ service_id ]
|
||||
|
||||
if service_type == HC.TAG_REPOSITORY: self._ClearCombinedAutocompleteTags()
|
||||
if service_type == HC.TAG_REPOSITORY:
|
||||
|
||||
job_key.SetVariable( 'popup_text_1', prefix + ': recomputing combined tags' )
|
||||
|
||||
self._ClearCombinedAutocompleteTags()
|
||||
|
||||
|
||||
if service_type in HC.REPOSITORIES:
|
||||
|
||||
job_key.SetVariable( 'popup_text_1', prefix + ': deleting downloaded updates' )
|
||||
|
||||
if delete_updates:
|
||||
|
||||
updates_dir = ClientFiles.GetExpectedUpdateDir( service_key )
|
||||
|
||||
if os.path.exists( updates_dir ):
|
||||
|
||||
HydrusData.DeletePath( updates_dir )
|
||||
|
||||
|
||||
info[ 'first_timestamp' ] = None
|
||||
info[ 'next_download_timestamp' ] = 0
|
||||
|
||||
|
||||
info[ 'next_processing_timestamp' ] = 0
|
||||
|
||||
self.pub_after_commit( 'notify_restart_repo_sync_daemon' )
|
||||
|
||||
|
||||
job_key.SetVariable( 'popup_text_1', prefix + ': recreating service' )
|
||||
|
||||
self._AddService( service_key, service_type, name, info )
|
||||
|
||||
self.pub_service_updates_after_commit( { service_key : [ HydrusData.ServiceUpdate( HC.SERVICE_UPDATE_RESET ) ] } )
|
||||
self.pub_after_commit( 'notify_new_pending' )
|
||||
self.pub_after_commit( 'notify_new_services_data' )
|
||||
self.pub_after_commit( 'notify_new_services_gui' )
|
||||
HydrusData.ShowText( 'Service ' + name + ' was reset successfully!' )
|
||||
|
||||
job_key.SetVariable( 'popup_text_1', prefix + ': done!' )
|
||||
|
||||
job_key.Finish()
|
||||
|
||||
|
||||
def _SaveOptions( self, options ):
|
||||
|
@ -5670,6 +5710,41 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
|
||||
|
||||
if version == 171:
|
||||
|
||||
self._controller.pub( 'splash_set_text', 'moving updates about' )
|
||||
|
||||
for filename in os.listdir( HC.CLIENT_UPDATES_DIR ):
|
||||
|
||||
try:
|
||||
|
||||
( service_key_encoded, gumpf ) = filename.split( '_', 1 )
|
||||
|
||||
except ValueError:
|
||||
|
||||
continue
|
||||
|
||||
|
||||
dest_dir = HC.CLIENT_UPDATES_DIR + os.path.sep + service_key_encoded
|
||||
|
||||
if not os.path.exists( dest_dir ):
|
||||
|
||||
os.mkdir( dest_dir )
|
||||
|
||||
|
||||
source_path = HC.CLIENT_UPDATES_DIR + os.path.sep + filename
|
||||
dest_path = dest_dir + os.path.sep + gumpf
|
||||
|
||||
shutil.move( source_path, dest_path )
|
||||
|
||||
|
||||
#
|
||||
|
||||
service_ids = self._GetServiceIds( ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ) )
|
||||
|
||||
for service_id in service_ids: self._c.execute( 'DELETE FROM service_info WHERE service_id = ?;', ( service_id, ) )
|
||||
|
||||
|
||||
self._controller.pub( 'splash_set_text', 'updating db to v' + HydrusData.ToString( version + 1 ) )
|
||||
|
||||
self._c.execute( 'UPDATE version SET version = ?;', ( version + 1, ) )
|
||||
|
@ -6014,18 +6089,11 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self.pub_service_updates_after_commit( service_keys_to_service_updates )
|
||||
|
||||
service_key_hex = server_service_key.encode( 'hex' )
|
||||
update_dir = ClientFiles.GetExpectedUpdateDir( server_service_key )
|
||||
|
||||
all_update_filenames = os.listdir( HC.CLIENT_UPDATES_DIR )
|
||||
|
||||
for filename in all_update_filenames:
|
||||
if os.path.exists( update_dir ):
|
||||
|
||||
if filename.startswith( service_key_hex ):
|
||||
|
||||
path = HC.CLIENT_UPDATES_DIR + os.path.sep + filename
|
||||
|
||||
HydrusData.DeletePath( path )
|
||||
|
||||
HydrusData.DeletePath( update_dir )
|
||||
|
||||
|
||||
if service_type == HC.TAG_REPOSITORY: clear_combined_autocomplete = True
|
||||
|
@ -6078,7 +6146,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
service = self._GetService( service_id )
|
||||
|
||||
if service.GetServiceType() == HC.TAG_REPOSITORY: clear_combined_autocomplete = True
|
||||
service_type = service.GetServiceType()
|
||||
|
||||
self._c.execute( 'DELETE FROM services WHERE service_id = ?;', ( service_id, ) )
|
||||
|
||||
|
@ -6090,19 +6158,14 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
self.pub_service_updates_after_commit( service_keys_to_service_updates )
|
||||
|
||||
service_key_hex = service_key.encode( 'hex' )
|
||||
update_dir = ClientFiles.GetExpectedUpdateDir( service_key )
|
||||
|
||||
all_update_filenames = os.listdir( HC.CLIENT_UPDATES_DIR )
|
||||
if os.path.exists( update_dir ):
|
||||
|
||||
HydrusData.DeletePath( update_dir )
|
||||
|
||||
|
||||
for filename in all_update_filenames:
|
||||
|
||||
if filename.startswith( service_key_hex ):
|
||||
|
||||
path = HC.CLIENT_UPDATES_DIR + os.path.sep + filename
|
||||
|
||||
HydrusData.DeletePath( path )
|
||||
|
||||
|
||||
if service_type == HC.TAG_REPOSITORY: clear_combined_autocomplete = True
|
||||
|
||||
elif action == HC.EDIT:
|
||||
|
||||
|
|
|
@ -1734,6 +1734,8 @@ class Service( HydrusData.HydrusYAMLBase ):
|
|||
|
||||
num_updates_processed += 1
|
||||
|
||||
time.sleep( 0.1 )
|
||||
|
||||
|
||||
job_key.DeleteVariable( 'popup_gauge_1' )
|
||||
job_key.DeleteVariable( 'popup_text_2' )
|
||||
|
|
|
@ -38,6 +38,8 @@ def GetClientDefaultOptions():
|
|||
options[ 'remove_trashed_files' ] = False
|
||||
options[ 'remove_filtered_files' ] = False
|
||||
options[ 'external_host' ] = None
|
||||
options[ 'gallery_file_limit' ] = 200
|
||||
options[ 'always_embed_autocompletes' ] = HC.PLATFORM_LINUX or HC.PLATFORM_OSX
|
||||
|
||||
system_predicates = {}
|
||||
|
||||
|
|
|
@ -413,7 +413,7 @@ class GalleryParserBooru( GalleryParser ):
|
|||
|
||||
|
||||
|
||||
return self._search_url.replace( '%tags%', self._search_separator.join( [ urllib.quote( tag, '' ) for tag in tags_to_use ] ) ).replace( '%index%', HydrusData.ToString( url_index ) )
|
||||
return self._search_url.replace( '%tags%', self._search_separator.join( [ urllib.quote( tag.encode( 'utf-8' ), '' ) for tag in tags_to_use ] ) ).replace( '%index%', HydrusData.ToString( url_index ) )
|
||||
|
||||
|
||||
def _ParseGalleryPage( self, html, url_base ):
|
||||
|
@ -736,7 +736,7 @@ class GalleryParserGiphy( GalleryParser ):
|
|||
|
||||
def __init__( self, tag ):
|
||||
|
||||
self._gallery_url = 'http://giphy.com/api/gifs?tag=' + urllib.quote( tag.replace( ' ', '+' ), '' ) + '&page='
|
||||
self._gallery_url = 'http://giphy.com/api/gifs?tag=' + urllib.quote( tag.encode( 'utf-8' ).replace( ' ', '+' ), '' ) + '&page='
|
||||
|
||||
GalleryParser.__init__( self )
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import HydrusSerialisable
|
|||
import itertools
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import shutil
|
||||
import stat
|
||||
import wx
|
||||
|
@ -60,6 +61,15 @@ def GenerateExportFilename( media, terms ):
|
|||
|
||||
|
||||
|
||||
if HC.PLATFORM_WINDOWS:
|
||||
|
||||
filename = re.sub( '\\\\|/|:|\\*|\\?|"|<|>|\\|', '_', filename, flags = re.UNICODE )
|
||||
|
||||
else:
|
||||
|
||||
filename = re.sub( '/', '_', filename, flags = re.UNICODE )
|
||||
|
||||
|
||||
return filename
|
||||
|
||||
def GetAllPaths( raw_paths ):
|
||||
|
@ -204,11 +214,15 @@ def GetThumbnailPath( hash, full_size = True ):
|
|||
|
||||
def GetExpectedContentUpdatePackagePath( service_key, begin, subindex ):
|
||||
|
||||
return HC.CLIENT_UPDATES_DIR + os.path.sep + service_key.encode( 'hex' ) + '_' + str( begin ) + '_' + str( subindex ) + '.json'
|
||||
return GetExpectedUpdateDir( service_key ) + os.path.sep + str( begin ) + '_' + str( subindex ) + '.json'
|
||||
|
||||
def GetExpectedServiceUpdatePackagePath( service_key, begin ):
|
||||
|
||||
return HC.CLIENT_UPDATES_DIR + os.path.sep + service_key.encode( 'hex' ) + '_' + str( begin ) + '_metadata.json'
|
||||
return GetExpectedUpdateDir( service_key ) + os.path.sep + str( begin ) + '_metadata.json'
|
||||
|
||||
def GetExpectedUpdateDir( service_key ):
|
||||
|
||||
return HC.CLIENT_UPDATES_DIR + os.path.sep + service_key.encode( 'hex' )
|
||||
|
||||
def IterateAllFileHashes():
|
||||
|
||||
|
|
|
@ -50,8 +50,8 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
self.SetDropTarget( ClientDragDrop.FileDropTarget( self.ImportFiles ) )
|
||||
|
||||
self._statusbar = self.CreateStatusBar()
|
||||
self._statusbar.SetFieldsCount( 3 )
|
||||
self._statusbar.SetStatusWidths( [ -1, 25, 50 ] )
|
||||
self._statusbar.SetFieldsCount( 4 )
|
||||
self._statusbar.SetStatusWidths( [ -1, 25, 25, 50 ] )
|
||||
|
||||
self._focus_holder = wx.Window( self, size = ( 0, 0 ) )
|
||||
|
||||
|
@ -64,7 +64,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
|
||||
self._tab_right_click_index = -1
|
||||
|
||||
HydrusGlobals.controller.SetTopWindow( self )
|
||||
wx.GetApp().SetTopWindow( self )
|
||||
|
||||
self.RefreshAcceleratorTable()
|
||||
|
||||
|
@ -242,19 +242,26 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
|
||||
HydrusData.ShowText( u'Starting server\u2026' )
|
||||
|
||||
my_scriptname = sys.argv[0]
|
||||
if HC.PLATFORM_WINDOWS:
|
||||
|
||||
my_exe = HC.BASE_DIR + os.path.sep + 'client.exe'
|
||||
|
||||
else:
|
||||
|
||||
my_exe = HC.BASE_DIR + os.path.sep + 'client'
|
||||
|
||||
|
||||
if my_scriptname.endswith( 'pyw' ):
|
||||
if sys.executable == my_exe:
|
||||
|
||||
if HC.PLATFORM_WINDOWS: subprocess.Popen( [ HC.BASE_DIR + os.path.sep + 'server.exe' ] )
|
||||
else: subprocess.Popen( [ '.' + HC.BASE_DIR + os.path.sep + 'server' ] )
|
||||
|
||||
else:
|
||||
|
||||
if HC.PLATFORM_WINDOWS or HC.PLATFORM_OSX: python_bin = 'pythonw'
|
||||
else: python_bin = 'python'
|
||||
|
||||
subprocess.Popen( [ python_bin, HC.BASE_DIR + os.path.sep + 'server.pyw' ] )
|
||||
|
||||
else:
|
||||
|
||||
if HC.PLATFORM_WINDOWS: subprocess.Popen( [ HC.BASE_DIR + os.path.sep + 'server.exe' ] )
|
||||
else: subprocess.Popen( [ './' + HC.BASE_DIR + os.path.sep + 'server' ] )
|
||||
subprocess.Popen( [ python_bin, HC.BASE_DIR + os.path.sep + 'server.py' ] )
|
||||
|
||||
|
||||
time_waited = 0
|
||||
|
@ -468,7 +475,10 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
if polite:
|
||||
|
||||
try: page.TestAbleToClose()
|
||||
except: return
|
||||
except HydrusExceptions.PermissionException:
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
page.Pause()
|
||||
|
@ -967,6 +977,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
debug.AppendCheckItem( db_profile_mode_id, p( '&DB Profile Mode' ) )
|
||||
debug.Check( db_profile_mode_id, HydrusGlobals.db_profile_mode )
|
||||
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'force_idle' ), p( 'Force Idle Mode' ) )
|
||||
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'force_unbusy' ), p( 'Force Unbusy Mode' ) )
|
||||
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'debug_garbage' ), p( 'Garbage' ) )
|
||||
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'clear_caches' ), p( '&Clear Caches' ) )
|
||||
|
||||
|
@ -1061,7 +1072,10 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
for page in [ self._notebook.GetPage( i ) for i in range( self._notebook.GetPageCount() ) ]:
|
||||
|
||||
try: page.TestAbleToClose()
|
||||
except: return
|
||||
except HydrusExceptions.PermissionException:
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
while self._notebook.GetPageCount() > 0:
|
||||
|
@ -1371,6 +1385,15 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
idle_status = ''
|
||||
|
||||
|
||||
if HydrusGlobals.controller.SystemBusy():
|
||||
|
||||
busy_status = 'busy'
|
||||
|
||||
else:
|
||||
|
||||
busy_status = ''
|
||||
|
||||
|
||||
if HydrusGlobals.controller.GetDB().CurrentlyDoingJob():
|
||||
|
||||
db_status = 'db locked'
|
||||
|
@ -1382,7 +1405,8 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
|
|||
|
||||
self._statusbar.SetStatusText( media_status, number = 0 )
|
||||
self._statusbar.SetStatusText( idle_status, number = 1 )
|
||||
self._statusbar.SetStatusText( db_status, number = 2 )
|
||||
self._statusbar.SetStatusText( busy_status, number = 2 )
|
||||
self._statusbar.SetStatusText( db_status, number = 3 )
|
||||
|
||||
|
||||
def _RegenerateThumbnails( self ):
|
||||
|
@ -1984,6 +2008,9 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
elif command == 'force_idle':
|
||||
|
||||
HydrusGlobals.controller.ForceIdle()
|
||||
elif command == 'force_unbusy':
|
||||
|
||||
HydrusGlobals.controller.ForceUnbusy()
|
||||
|
||||
elif command == '8chan_board': webbrowser.open( 'http://8ch.net/hydrus/index.html' )
|
||||
elif command == 'file_integrity': self._CheckFileIntegrity()
|
||||
|
@ -2333,7 +2360,7 @@ class FrameReviewServices( ClientGUICommon.Frame ):
|
|||
|
||||
pos = ( pos_x + 25, pos_y + 50 )
|
||||
|
||||
tlp = HydrusGlobals.controller.GetTopWindow()
|
||||
tlp = wx.GetApp().GetTopWindow()
|
||||
|
||||
ClientGUICommon.Frame.__init__( self, tlp, title = HydrusGlobals.controller.PrepStringForDisplay( 'Review Services' ), pos = pos )
|
||||
|
||||
|
@ -2444,234 +2471,6 @@ class FrameReviewServices( ClientGUICommon.Frame ):
|
|||
|
||||
def __init__( self, parent, service_key ):
|
||||
|
||||
def InitialiseControls():
|
||||
|
||||
if service_type in HC.REPOSITORIES + HC.LOCAL_SERVICES:
|
||||
|
||||
self._info_panel = ClientGUICommon.StaticBox( self, 'service information' )
|
||||
|
||||
if service_type in ( HC.LOCAL_FILE, HC.FILE_REPOSITORY ):
|
||||
|
||||
self._files_text = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
self._deleted_files_text = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
if service_type == HC.FILE_REPOSITORY:
|
||||
|
||||
self._num_thumbs = 0
|
||||
self._num_local_thumbs = 0
|
||||
|
||||
self._thumbnails = ClientGUICommon.Gauge( self._info_panel )
|
||||
|
||||
self._thumbnails_text = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
|
||||
elif service_type in ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ):
|
||||
|
||||
self._tags_text = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
if service_type == HC.TAG_REPOSITORY:
|
||||
|
||||
self._deleted_tags_text = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
|
||||
elif service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ):
|
||||
|
||||
self._ratings_text = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
elif service_type == HC.LOCAL_BOORU:
|
||||
|
||||
self._num_shares = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
self._bytes = ClientGUICommon.Gauge( self._info_panel )
|
||||
|
||||
self._bytes_text = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
|
||||
|
||||
if service_type in HC.RESTRICTED_SERVICES:
|
||||
|
||||
self._permissions_panel = ClientGUICommon.StaticBox( self, 'service permissions' )
|
||||
|
||||
self._account_type = wx.StaticText( self._permissions_panel, style = wx.ALIGN_CENTER )
|
||||
|
||||
self._age = ClientGUICommon.Gauge( self._permissions_panel )
|
||||
|
||||
self._age_text = wx.StaticText( self._permissions_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
self._bytes = ClientGUICommon.Gauge( self._permissions_panel )
|
||||
|
||||
self._bytes_text = wx.StaticText( self._permissions_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
self._requests = ClientGUICommon.Gauge( self._permissions_panel )
|
||||
|
||||
self._requests_text = wx.StaticText( self._permissions_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
|
||||
if service_type in HC.REPOSITORIES:
|
||||
|
||||
self._synchro_panel = ClientGUICommon.StaticBox( self, 'repository synchronisation' )
|
||||
|
||||
self._updates = ClientGUICommon.Gauge( self._synchro_panel )
|
||||
|
||||
self._updates_text = wx.StaticText( self._synchro_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
|
||||
if service_type == HC.LOCAL_BOORU:
|
||||
|
||||
self._booru_shares_panel = ClientGUICommon.StaticBox( self, 'shares' )
|
||||
|
||||
self._booru_shares = ClientGUICommon.SaneListCtrl( self._booru_shares_panel, -1, [ ( 'title', 110 ), ( 'text', -1 ), ( 'expires', 170 ), ( 'num files', 70 ) ], delete_key_callback = self.DeleteBoorus )
|
||||
|
||||
self._booru_open_search = wx.Button( self._booru_shares_panel, label = 'open share in new page' )
|
||||
self._booru_open_search.Bind( wx.EVT_BUTTON, self.EventBooruOpenSearch )
|
||||
|
||||
self._copy_internal_share_link = wx.Button( self._booru_shares_panel, label = 'copy internal share link' )
|
||||
self._copy_internal_share_link.Bind( wx.EVT_BUTTON, self.EventCopyInternalShareURL )
|
||||
|
||||
self._copy_external_share_link = wx.Button( self._booru_shares_panel, label = 'copy external share link' )
|
||||
self._copy_external_share_link.Bind( wx.EVT_BUTTON, self.EventCopyExternalShareURL )
|
||||
|
||||
self._booru_edit = wx.Button( self._booru_shares_panel, label = 'edit' )
|
||||
self._booru_edit.Bind( wx.EVT_BUTTON, self.EventBooruEdit )
|
||||
|
||||
self._booru_delete = wx.Button( self._booru_shares_panel, label = 'delete' )
|
||||
self._booru_delete.Bind( wx.EVT_BUTTON, self.EventBooruDelete )
|
||||
|
||||
|
||||
if service_type in ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ):
|
||||
|
||||
self._service_wide_update = wx.Button( self, label = 'perform a service-wide operation' )
|
||||
self._service_wide_update.Bind( wx.EVT_BUTTON, self.EventServiceWideUpdate )
|
||||
|
||||
|
||||
if service_type == HC.SERVER_ADMIN:
|
||||
|
||||
self._init = wx.Button( self, label = 'initialise server' )
|
||||
self._init.Bind( wx.EVT_BUTTON, self.EventServerInitialise )
|
||||
|
||||
|
||||
if service_type in HC.RESTRICTED_SERVICES:
|
||||
|
||||
self._refresh = wx.Button( self, label = 'refresh account' )
|
||||
self._refresh.Bind( wx.EVT_BUTTON, self.EventServiceRefreshAccount )
|
||||
|
||||
self._copy_account_key = wx.Button( self, label = 'copy account key' )
|
||||
self._copy_account_key.Bind( wx.EVT_BUTTON, self.EventCopyAccountKey )
|
||||
|
||||
|
||||
|
||||
def PopulateControls():
|
||||
|
||||
self._DisplayService()
|
||||
|
||||
|
||||
def ArrangeControls():
|
||||
|
||||
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
||||
|
||||
vbox = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
if service_type in HC.REPOSITORIES + HC.LOCAL_SERVICES:
|
||||
|
||||
if service_type in ( HC.LOCAL_FILE, HC.FILE_REPOSITORY ):
|
||||
|
||||
self._info_panel.AddF( self._files_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
self._info_panel.AddF( self._deleted_files_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
if service_type == HC.FILE_REPOSITORY:
|
||||
|
||||
self._info_panel.AddF( self._thumbnails, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._info_panel.AddF( self._thumbnails_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
elif service_type in ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ):
|
||||
|
||||
self._info_panel.AddF( self._tags_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
if service_type == HC.TAG_REPOSITORY:
|
||||
|
||||
self._info_panel.AddF( self._deleted_tags_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
elif service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ):
|
||||
|
||||
self._info_panel.AddF( self._ratings_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
elif service_type == HC.LOCAL_BOORU:
|
||||
|
||||
self._info_panel.AddF( self._num_shares, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._info_panel.AddF( self._bytes, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._info_panel.AddF( self._bytes_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
vbox.AddF( self._info_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
if service_type in HC.RESTRICTED_SERVICES:
|
||||
|
||||
self._permissions_panel.AddF( self._account_type, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._permissions_panel.AddF( self._age, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._permissions_panel.AddF( self._age_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._permissions_panel.AddF( self._bytes, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._permissions_panel.AddF( self._bytes_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._permissions_panel.AddF( self._requests, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._permissions_panel.AddF( self._requests_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
vbox.AddF( self._permissions_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
if service_type in HC.REPOSITORIES:
|
||||
|
||||
self._synchro_panel.AddF( self._updates, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._synchro_panel.AddF( self._updates_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
vbox.AddF( self._synchro_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
if service_type == HC.LOCAL_BOORU:
|
||||
|
||||
self._booru_shares_panel.AddF( self._booru_shares, CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
|
||||
b_box = wx.BoxSizer( wx.HORIZONTAL )
|
||||
b_box.AddF( self._booru_open_search, CC.FLAGS_MIXED )
|
||||
b_box.AddF( self._copy_internal_share_link, CC.FLAGS_MIXED )
|
||||
b_box.AddF( self._copy_external_share_link, CC.FLAGS_MIXED )
|
||||
b_box.AddF( self._booru_edit, CC.FLAGS_MIXED )
|
||||
b_box.AddF( self._booru_delete, CC.FLAGS_MIXED )
|
||||
|
||||
self._booru_shares_panel.AddF( b_box, CC.FLAGS_BUTTON_SIZER )
|
||||
|
||||
vbox.AddF( self._booru_shares_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
|
||||
|
||||
if service_type in HC.RESTRICTED_SERVICES + [ HC.LOCAL_TAG ]:
|
||||
|
||||
repo_buttons_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
if service_type in ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ):
|
||||
|
||||
repo_buttons_hbox.AddF( self._service_wide_update, CC.FLAGS_MIXED )
|
||||
|
||||
|
||||
if service_type == HC.SERVER_ADMIN:
|
||||
|
||||
repo_buttons_hbox.AddF( self._init, CC.FLAGS_MIXED )
|
||||
|
||||
|
||||
if service_type in HC.RESTRICTED_SERVICES:
|
||||
|
||||
repo_buttons_hbox.AddF( self._refresh, CC.FLAGS_MIXED )
|
||||
repo_buttons_hbox.AddF( self._copy_account_key, CC.FLAGS_MIXED )
|
||||
|
||||
|
||||
vbox.AddF( repo_buttons_hbox, CC.FLAGS_BUTTON_SIZER )
|
||||
|
||||
|
||||
self.SetSizer( vbox )
|
||||
|
||||
|
||||
wx.ScrolledWindow.__init__( self, parent )
|
||||
|
||||
self.SetScrollRate( 0, 20 )
|
||||
|
@ -2682,11 +2481,232 @@ class FrameReviewServices( ClientGUICommon.Frame ):
|
|||
|
||||
service_type = self._service.GetServiceType()
|
||||
|
||||
InitialiseControls()
|
||||
if service_type in HC.REPOSITORIES + HC.LOCAL_SERVICES:
|
||||
|
||||
self._info_panel = ClientGUICommon.StaticBox( self, 'service information' )
|
||||
|
||||
if service_type in ( HC.LOCAL_FILE, HC.FILE_REPOSITORY ):
|
||||
|
||||
self._files_text = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
self._deleted_files_text = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
if service_type == HC.FILE_REPOSITORY:
|
||||
|
||||
self._num_thumbs = 0
|
||||
self._num_local_thumbs = 0
|
||||
|
||||
self._thumbnails = ClientGUICommon.Gauge( self._info_panel )
|
||||
|
||||
self._thumbnails_text = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
|
||||
elif service_type in ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ):
|
||||
|
||||
self._tags_text = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
if service_type == HC.TAG_REPOSITORY:
|
||||
|
||||
self._deleted_tags_text = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
|
||||
elif service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ):
|
||||
|
||||
self._ratings_text = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
elif service_type == HC.LOCAL_BOORU:
|
||||
|
||||
self._num_shares = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
self._bytes = ClientGUICommon.Gauge( self._info_panel )
|
||||
|
||||
self._bytes_text = wx.StaticText( self._info_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
|
||||
|
||||
PopulateControls()
|
||||
if service_type in HC.RESTRICTED_SERVICES:
|
||||
|
||||
self._permissions_panel = ClientGUICommon.StaticBox( self, 'service permissions' )
|
||||
|
||||
self._account_type = wx.StaticText( self._permissions_panel, style = wx.ALIGN_CENTER )
|
||||
|
||||
self._age = ClientGUICommon.Gauge( self._permissions_panel )
|
||||
|
||||
self._age_text = wx.StaticText( self._permissions_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
self._bytes = ClientGUICommon.Gauge( self._permissions_panel )
|
||||
|
||||
self._bytes_text = wx.StaticText( self._permissions_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
self._requests = ClientGUICommon.Gauge( self._permissions_panel )
|
||||
|
||||
self._requests_text = wx.StaticText( self._permissions_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
|
||||
ArrangeControls()
|
||||
if service_type in HC.REPOSITORIES:
|
||||
|
||||
self._synchro_panel = ClientGUICommon.StaticBox( self, 'repository synchronisation' )
|
||||
|
||||
self._updates = ClientGUICommon.Gauge( self._synchro_panel )
|
||||
|
||||
self._updates_text = wx.StaticText( self._synchro_panel, style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
||||
|
||||
self._immediate_sync = wx.Button( self._synchro_panel, label = 'sync now' )
|
||||
self._immediate_sync.Bind( wx.EVT_BUTTON, self.EventImmediateSync)
|
||||
|
||||
|
||||
if service_type == HC.LOCAL_BOORU:
|
||||
|
||||
self._booru_shares_panel = ClientGUICommon.StaticBox( self, 'shares' )
|
||||
|
||||
self._booru_shares = ClientGUICommon.SaneListCtrl( self._booru_shares_panel, -1, [ ( 'title', 110 ), ( 'text', -1 ), ( 'expires', 170 ), ( 'num files', 70 ) ], delete_key_callback = self.DeleteBoorus )
|
||||
|
||||
self._booru_open_search = wx.Button( self._booru_shares_panel, label = 'open share in new page' )
|
||||
self._booru_open_search.Bind( wx.EVT_BUTTON, self.EventBooruOpenSearch )
|
||||
|
||||
self._copy_internal_share_link = wx.Button( self._booru_shares_panel, label = 'copy internal share link' )
|
||||
self._copy_internal_share_link.Bind( wx.EVT_BUTTON, self.EventCopyInternalShareURL )
|
||||
|
||||
self._copy_external_share_link = wx.Button( self._booru_shares_panel, label = 'copy external share link' )
|
||||
self._copy_external_share_link.Bind( wx.EVT_BUTTON, self.EventCopyExternalShareURL )
|
||||
|
||||
self._booru_edit = wx.Button( self._booru_shares_panel, label = 'edit' )
|
||||
self._booru_edit.Bind( wx.EVT_BUTTON, self.EventBooruEdit )
|
||||
|
||||
self._booru_delete = wx.Button( self._booru_shares_panel, label = 'delete' )
|
||||
self._booru_delete.Bind( wx.EVT_BUTTON, self.EventBooruDelete )
|
||||
|
||||
|
||||
if service_type in ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ):
|
||||
|
||||
self._service_wide_update = wx.Button( self, label = 'perform a service-wide operation' )
|
||||
self._service_wide_update.Bind( wx.EVT_BUTTON, self.EventServiceWideUpdate )
|
||||
|
||||
|
||||
if service_type == HC.SERVER_ADMIN:
|
||||
|
||||
self._init = wx.Button( self, label = 'initialise server' )
|
||||
self._init.Bind( wx.EVT_BUTTON, self.EventServerInitialise )
|
||||
|
||||
|
||||
if service_type in HC.RESTRICTED_SERVICES:
|
||||
|
||||
self._refresh = wx.Button( self, label = 'refresh account' )
|
||||
self._refresh.Bind( wx.EVT_BUTTON, self.EventServiceRefreshAccount )
|
||||
|
||||
self._copy_account_key = wx.Button( self, label = 'copy account key' )
|
||||
self._copy_account_key.Bind( wx.EVT_BUTTON, self.EventCopyAccountKey )
|
||||
|
||||
|
||||
#
|
||||
|
||||
self._DisplayService()
|
||||
|
||||
#
|
||||
|
||||
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
||||
|
||||
vbox = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
if service_type in HC.REPOSITORIES + HC.LOCAL_SERVICES:
|
||||
|
||||
if service_type in ( HC.LOCAL_FILE, HC.FILE_REPOSITORY ):
|
||||
|
||||
self._info_panel.AddF( self._files_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
self._info_panel.AddF( self._deleted_files_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
if service_type == HC.FILE_REPOSITORY:
|
||||
|
||||
self._info_panel.AddF( self._thumbnails, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._info_panel.AddF( self._thumbnails_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
elif service_type in ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ):
|
||||
|
||||
self._info_panel.AddF( self._tags_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
if service_type == HC.TAG_REPOSITORY:
|
||||
|
||||
self._info_panel.AddF( self._deleted_tags_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
elif service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ):
|
||||
|
||||
self._info_panel.AddF( self._ratings_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
elif service_type == HC.LOCAL_BOORU:
|
||||
|
||||
self._info_panel.AddF( self._num_shares, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._info_panel.AddF( self._bytes, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._info_panel.AddF( self._bytes_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
vbox.AddF( self._info_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
if service_type in HC.RESTRICTED_SERVICES:
|
||||
|
||||
self._permissions_panel.AddF( self._account_type, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._permissions_panel.AddF( self._age, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._permissions_panel.AddF( self._age_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._permissions_panel.AddF( self._bytes, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._permissions_panel.AddF( self._bytes_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._permissions_panel.AddF( self._requests, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._permissions_panel.AddF( self._requests_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
vbox.AddF( self._permissions_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
if service_type in HC.REPOSITORIES:
|
||||
|
||||
self._synchro_panel.AddF( self._updates, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._synchro_panel.AddF( self._updates_text, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
self._synchro_panel.AddF( self._immediate_sync, CC.FLAGS_LONE_BUTTON )
|
||||
|
||||
vbox.AddF( self._synchro_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
if service_type == HC.LOCAL_BOORU:
|
||||
|
||||
self._booru_shares_panel.AddF( self._booru_shares, CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
|
||||
b_box = wx.BoxSizer( wx.HORIZONTAL )
|
||||
b_box.AddF( self._booru_open_search, CC.FLAGS_MIXED )
|
||||
b_box.AddF( self._copy_internal_share_link, CC.FLAGS_MIXED )
|
||||
b_box.AddF( self._copy_external_share_link, CC.FLAGS_MIXED )
|
||||
b_box.AddF( self._booru_edit, CC.FLAGS_MIXED )
|
||||
b_box.AddF( self._booru_delete, CC.FLAGS_MIXED )
|
||||
|
||||
self._booru_shares_panel.AddF( b_box, CC.FLAGS_BUTTON_SIZER )
|
||||
|
||||
vbox.AddF( self._booru_shares_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
|
||||
|
||||
if service_type in HC.RESTRICTED_SERVICES + [ HC.LOCAL_TAG ]:
|
||||
|
||||
repo_buttons_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
if service_type in ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ):
|
||||
|
||||
repo_buttons_hbox.AddF( self._service_wide_update, CC.FLAGS_MIXED )
|
||||
|
||||
|
||||
if service_type == HC.SERVER_ADMIN:
|
||||
|
||||
repo_buttons_hbox.AddF( self._init, CC.FLAGS_MIXED )
|
||||
|
||||
|
||||
if service_type in HC.RESTRICTED_SERVICES:
|
||||
|
||||
repo_buttons_hbox.AddF( self._refresh, CC.FLAGS_MIXED )
|
||||
repo_buttons_hbox.AddF( self._copy_account_key, CC.FLAGS_MIXED )
|
||||
|
||||
|
||||
vbox.AddF( repo_buttons_hbox, CC.FLAGS_BUTTON_SIZER )
|
||||
|
||||
|
||||
self.SetSizer( vbox )
|
||||
|
||||
self._timer_updates = wx.Timer( self, id = ID_TIMER_UPDATES )
|
||||
|
||||
|
@ -2815,6 +2835,15 @@ class FrameReviewServices( ClientGUICommon.Frame ):
|
|||
|
||||
self._updates_text.SetLabel( self._service.GetUpdateStatus() )
|
||||
|
||||
if account.HasPermission( HC.RESOLVE_PETITIONS ):
|
||||
|
||||
self._immediate_sync.Show()
|
||||
|
||||
else:
|
||||
|
||||
self._immediate_sync.Hide()
|
||||
|
||||
|
||||
|
||||
self._refresh.Enable()
|
||||
|
||||
|
@ -3034,6 +3063,91 @@ class FrameReviewServices( ClientGUICommon.Frame ):
|
|||
|
||||
|
||||
|
||||
def EventImmediateSync( self, event ):
|
||||
|
||||
def do_it():
|
||||
|
||||
job_key = HydrusData.JobKey( pausable = True, cancellable = True )
|
||||
|
||||
job_key.SetVariable( 'popup_title', self._service.GetName() + ': immediate sync' )
|
||||
job_key.SetVariable( 'popup_text_1', 'downloading' )
|
||||
|
||||
HydrusGlobals.controller.pub( 'message', job_key )
|
||||
|
||||
content_update_package = self._service.Request( HC.GET, 'immediate_content_update_package' )
|
||||
|
||||
c_u_p_num_rows = content_update_package.GetNumRows()
|
||||
c_u_p_total_weight_processed = 0
|
||||
|
||||
pending_content_updates = []
|
||||
pending_weight = 0
|
||||
|
||||
update_speed_string = ''
|
||||
|
||||
content_update_index_string = 'content row ' + HydrusData.ConvertValueRangeToPrettyString( c_u_p_total_weight_processed, c_u_p_num_rows ) + ': '
|
||||
|
||||
job_key.SetVariable( 'popup_text_1', content_update_index_string + 'committing' + update_speed_string )
|
||||
|
||||
job_key.SetVariable( 'popup_gauge_1', ( c_u_p_total_weight_processed, c_u_p_num_rows ) )
|
||||
|
||||
for content_update in content_update_package.IterateContentUpdates():
|
||||
|
||||
( i_paused, should_quit ) = job_key.WaitIfNeeded()
|
||||
|
||||
if should_quit:
|
||||
|
||||
job_key.Delete()
|
||||
|
||||
return
|
||||
|
||||
|
||||
pending_content_updates.append( content_update )
|
||||
|
||||
content_update_weight = len( content_update.GetHashes() )
|
||||
|
||||
pending_weight += content_update_weight
|
||||
|
||||
if pending_weight > 100:
|
||||
|
||||
content_update_index_string = 'content row ' + HydrusData.ConvertValueRangeToPrettyString( c_u_p_total_weight_processed, c_u_p_num_rows ) + ': '
|
||||
|
||||
job_key.SetVariable( 'popup_text_1', content_update_index_string + 'committing' + update_speed_string )
|
||||
|
||||
job_key.SetVariable( 'popup_gauge_1', ( c_u_p_total_weight_processed, c_u_p_num_rows ) )
|
||||
|
||||
precise_timestamp = HydrusData.GetNowPrecise()
|
||||
|
||||
HydrusGlobals.controller.WriteSynchronous( 'content_updates', { self._service_key : pending_content_updates } )
|
||||
|
||||
it_took = HydrusData.GetNowPrecise() - precise_timestamp
|
||||
|
||||
rows_s = pending_weight / it_took
|
||||
|
||||
update_speed_string = ' at ' + HydrusData.ConvertIntToPrettyString( rows_s ) + ' rows/s'
|
||||
|
||||
c_u_p_total_weight_processed += pending_weight
|
||||
|
||||
pending_content_updates = []
|
||||
pending_weight = 0
|
||||
|
||||
|
||||
|
||||
if len( pending_content_updates ) > 0:
|
||||
|
||||
HydrusGlobals.controller.WriteSynchronous( { self._service_key : pending_content_updates } )
|
||||
|
||||
c_u_p_total_weight_processed += pending_weight
|
||||
|
||||
|
||||
job_key.SetVariable( 'popup_text_1', 'done! ' + HydrusData.ConvertIntToPrettyString( c_u_p_num_rows ) + ' rows added.' )
|
||||
job_key.DeleteVariable( 'popup_gauge_1' )
|
||||
|
||||
job_key.Finish()
|
||||
|
||||
|
||||
HydrusGlobals.controller.CallToThread( do_it )
|
||||
|
||||
|
||||
def EventServiceWideUpdate( self, event ):
|
||||
|
||||
with ClientGUIDialogs.DialogAdvancedContentUpdate( self, self._service_key ) as dlg:
|
||||
|
@ -3116,7 +3230,7 @@ class FrameSeedCache( ClientGUICommon.Frame ):
|
|||
|
||||
pos = ( pos_x + 25, pos_y + 50 )
|
||||
|
||||
tlp = HydrusGlobals.controller.GetTopWindow()
|
||||
tlp = wx.GetApp().GetTopWindow()
|
||||
|
||||
ClientGUICommon.Frame.__init__( self, tlp, title = HydrusGlobals.controller.PrepStringForDisplay( 'File Import Status' ), pos = pos )
|
||||
|
||||
|
|
|
@ -936,12 +936,34 @@ class Canvas( object ):
|
|||
|
||||
def KeepCursorAlive( self ): pass
|
||||
|
||||
def MouseIsNearAnimationBar( self ):
|
||||
|
||||
if ShouldHaveAnimationBar( self._current_display_media ):
|
||||
|
||||
animation_bar = self._media_container.GetAnimationBar()
|
||||
|
||||
( x, y ) = animation_bar.GetScreenPosition()
|
||||
( width, height ) = animation_bar.GetSize()
|
||||
|
||||
( mouse_x, mouse_y ) = wx.GetMousePosition()
|
||||
|
||||
buffer_distance = 75
|
||||
|
||||
if mouse_x >= x - buffer_distance and mouse_x <= x + width + buffer_distance and mouse_y >= y - buffer_distance and mouse_y <= y + height + buffer_distance:
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def MouseIsOverMedia( self ):
|
||||
|
||||
( x, y ) = self._media_container.GetPosition()
|
||||
( x, y ) = self._media_container.GetScreenPosition()
|
||||
( width, height ) = self._media_container.GetSize()
|
||||
|
||||
( mouse_x, mouse_y ) = self.ScreenToClient( wx.GetMousePosition() )
|
||||
( mouse_x, mouse_y ) = wx.GetMousePosition()
|
||||
|
||||
if mouse_x >= x and mouse_x <= x + width and mouse_y >= y and mouse_y <= y + height: return True
|
||||
|
||||
|
@ -1407,7 +1429,7 @@ class CanvasFullscreenMediaList( ClientMedia.ListeningMediaList, CanvasWithDetai
|
|||
|
||||
self.Show( True )
|
||||
|
||||
HydrusGlobals.controller.SetTopWindow( self )
|
||||
wx.GetApp().SetTopWindow( self )
|
||||
|
||||
self._timer_cursor_hide = wx.Timer( self, id = ID_TIMER_CURSOR_HIDE )
|
||||
|
||||
|
@ -2990,6 +3012,11 @@ class MediaContainer( wx.Window ):
|
|||
|
||||
|
||||
|
||||
def GetAnimationBar( self ):
|
||||
|
||||
return self._animation_bar
|
||||
|
||||
|
||||
def GotoPreviousOrNextFrame( self, direction ):
|
||||
|
||||
if self._media_window is not None:
|
||||
|
|
|
@ -85,7 +85,7 @@ class AutoCompleteDropdown( wx.Panel ):
|
|||
# There's a big bug in wx where FRAME_FLOAT_ON_PARENT Frames don't get passed their mouse events if their parent is a Dialog jej
|
||||
# I think it is something to do with the initialisation order; if the frame is init'ed before the ShowModal call, but whatever.
|
||||
|
||||
if issubclass( type( tlp ), wx.Dialog ): self._float_mode = False
|
||||
if issubclass( type( tlp ), wx.Dialog ) or HC.options[ 'always_embed_autocompletes' ]: self._float_mode = False
|
||||
else: self._float_mode = True
|
||||
|
||||
self._text_ctrl = wx.TextCtrl( self, style=wx.TE_PROCESS_ENTER )
|
||||
|
@ -693,7 +693,7 @@ class AutoCompleteDropdownTagsRead( AutoCompleteDropdownTags ):
|
|||
|
||||
( inclusive, search_text, entry_predicate ) = self._ParseSearchText()
|
||||
|
||||
if search_text == '':
|
||||
if search_text in ( '', ':' ):
|
||||
|
||||
self._cache_text = ''
|
||||
self._current_namespace = ''
|
||||
|
@ -990,7 +990,7 @@ class AutoCompleteDropdownTagsWrite( AutoCompleteDropdownTags ):
|
|||
|
||||
( search_text, entry_predicate, sibling_predicate ) = self._ParseSearchText()
|
||||
|
||||
if search_text == '':
|
||||
if search_text in ( '', ':' ):
|
||||
|
||||
self._cache_text = ''
|
||||
self._current_namespace = ''
|
||||
|
|
|
@ -2840,7 +2840,7 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
|
|||
self._listbook.AddPage( 'local server', self._ServerPanel( self._listbook ) )
|
||||
self._listbook.AddPage( 'sort/collect', self._SortCollectPanel( self._listbook ) )
|
||||
self._listbook.AddPage( 'shortcuts', self._ShortcutsPanel( self._listbook ) )
|
||||
self._listbook.AddPage( 'thread checker', self._ThreadCheckerPanel( self._listbook ) )
|
||||
self._listbook.AddPage( 'downloading', self._DownloadingPanel( self._listbook ) )
|
||||
|
||||
self._ok = wx.Button( self, id = wx.ID_OK, label = 'Save' )
|
||||
self._ok.Bind( wx.EVT_BUTTON, self.EventOK )
|
||||
|
@ -3151,6 +3151,70 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
|
|||
|
||||
|
||||
|
||||
class _DownloadingPanel( wx.Panel ):
|
||||
|
||||
def __init__( self, parent ):
|
||||
|
||||
wx.Panel.__init__( self, parent )
|
||||
|
||||
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
||||
|
||||
gallery_downloader = ClientGUICommon.StaticBox( self, 'gallery downloader' )
|
||||
|
||||
self._gallery_file_limit = ClientGUICommon.NoneableSpinCtrl( gallery_downloader, 'default file limit', none_phrase = 'no limit', min = 1, max = 1000000 )
|
||||
|
||||
thread_checker = ClientGUICommon.StaticBox( self, 'thread checker' )
|
||||
|
||||
self._thread_times_to_check = wx.SpinCtrl( thread_checker, min = 0, max = 100 )
|
||||
self._thread_times_to_check.SetToolTipString( 'how many times the thread checker will check' )
|
||||
|
||||
self._thread_check_period = wx.SpinCtrl( thread_checker, min = 30, max = 86400 )
|
||||
self._thread_check_period.SetToolTipString( 'how long the checker will wait between checks' )
|
||||
|
||||
#
|
||||
|
||||
self._gallery_file_limit.SetValue( HC.options[ 'gallery_file_limit' ] )
|
||||
|
||||
( times_to_check, check_period ) = HC.options[ 'thread_checker_timings' ]
|
||||
|
||||
self._thread_times_to_check.SetValue( times_to_check )
|
||||
|
||||
self._thread_check_period.SetValue( check_period )
|
||||
|
||||
#
|
||||
|
||||
gallery_downloader.AddF( self._gallery_file_limit, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
#
|
||||
|
||||
gridbox = wx.FlexGridSizer( 0, 2 )
|
||||
|
||||
gridbox.AddGrowableCol( 1, 1 )
|
||||
|
||||
gridbox.AddF( wx.StaticText( thread_checker, label = 'default number of times to check: ' ), CC.FLAGS_MIXED )
|
||||
gridbox.AddF( self._thread_times_to_check, CC.FLAGS_MIXED )
|
||||
gridbox.AddF( wx.StaticText( thread_checker, label = 'default wait in seconds between checks: ' ), CC.FLAGS_MIXED )
|
||||
gridbox.AddF( self._thread_check_period, CC.FLAGS_MIXED )
|
||||
|
||||
thread_checker.AddF( gridbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
|
||||
|
||||
#
|
||||
|
||||
vbox = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
vbox.AddF( gallery_downloader, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
vbox.AddF( thread_checker, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
self.SetSizer( vbox )
|
||||
|
||||
|
||||
def UpdateOptions( self ):
|
||||
|
||||
HC.options[ 'gallery_file_limit' ] = self._gallery_file_limit.GetValue()
|
||||
HC.options[ 'thread_checker_timings' ] = ( self._thread_times_to_check.GetValue(), self._thread_check_period.GetValue() )
|
||||
|
||||
|
||||
|
||||
class _MaintenanceAndProcessingPanel( wx.Panel ):
|
||||
|
||||
def __init__( self, parent ):
|
||||
|
@ -3561,6 +3625,8 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
|
|||
|
||||
self._confirm_client_exit = wx.CheckBox( self )
|
||||
|
||||
self._always_embed_autocompletes = wx.CheckBox( self )
|
||||
|
||||
self._gui_capitalisation = wx.CheckBox( self )
|
||||
|
||||
self._gui_show_all_tags_in_autocomplete = wx.CheckBox( self )
|
||||
|
@ -3593,6 +3659,8 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
|
|||
|
||||
self._confirm_client_exit.SetValue( HC.options[ 'confirm_client_exit' ] )
|
||||
|
||||
self._always_embed_autocompletes.SetValue( HC.options[ 'always_embed_autocompletes' ] )
|
||||
|
||||
self._gui_capitalisation.SetValue( HC.options[ 'gui_capitalisation' ] )
|
||||
|
||||
self._gui_show_all_tags_in_autocomplete.SetValue( HC.options[ 'show_all_tags_in_autocomplete' ] )
|
||||
|
@ -3634,10 +3702,13 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
|
|||
gridbox.AddF( wx.StaticText( self, label = 'Confirm client exit:' ), CC.FLAGS_MIXED )
|
||||
gridbox.AddF( self._confirm_client_exit, CC.FLAGS_MIXED )
|
||||
|
||||
gridbox.AddF( wx.StaticText( self, label = 'Always embed autocomplete dropdown results window:' ), CC.FLAGS_MIXED )
|
||||
gridbox.AddF( self._always_embed_autocompletes, CC.FLAGS_MIXED )
|
||||
|
||||
gridbox.AddF( wx.StaticText( self, label = 'Default tag service in manage tag dialogs:' ), CC.FLAGS_MIXED )
|
||||
gridbox.AddF( self._default_tag_repository, CC.FLAGS_MIXED )
|
||||
|
||||
gridbox.AddF( wx.StaticText( self, label = 'Default tag sort on management panel:' ), CC.FLAGS_MIXED )
|
||||
gridbox.AddF( wx.StaticText( self, label = 'Default tag sort:' ), CC.FLAGS_MIXED )
|
||||
gridbox.AddF( self._default_tag_sort, CC.FLAGS_MIXED )
|
||||
|
||||
gridbox.AddF( wx.StaticText( self, label = 'Capitalise gui: ' ), CC.FLAGS_MIXED )
|
||||
|
@ -3662,6 +3733,7 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
|
|||
|
||||
HC.options[ 'default_gui_session' ] = self._default_gui_session.GetStringSelection()
|
||||
HC.options[ 'confirm_client_exit' ] = self._confirm_client_exit.GetValue()
|
||||
HC.options[ 'always_embed_autocompletes' ] = self._always_embed_autocompletes.GetValue()
|
||||
HC.options[ 'gui_capitalisation' ] = self._gui_capitalisation.GetValue()
|
||||
HC.options[ 'show_all_tags_in_autocomplete' ] = self._gui_show_all_tags_in_autocomplete.GetValue()
|
||||
HC.options[ 'default_tag_repository' ] = self._default_tag_repository.GetChoice()
|
||||
|
@ -4252,48 +4324,6 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
|
|||
|
||||
|
||||
|
||||
class _ThreadCheckerPanel( wx.Panel ):
|
||||
|
||||
def __init__( self, parent ):
|
||||
|
||||
wx.Panel.__init__( self, parent )
|
||||
|
||||
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
||||
|
||||
self._thread_times_to_check = wx.SpinCtrl( self, min = 0, max = 100 )
|
||||
self._thread_times_to_check.SetToolTipString( 'how many times the thread checker will check' )
|
||||
|
||||
self._thread_check_period = wx.SpinCtrl( self, min = 30, max = 86400 )
|
||||
self._thread_check_period.SetToolTipString( 'how long the checker will wait between checks' )
|
||||
|
||||
#
|
||||
|
||||
( times_to_check, check_period ) = HC.options[ 'thread_checker_timings' ]
|
||||
|
||||
self._thread_times_to_check.SetValue( times_to_check )
|
||||
|
||||
self._thread_check_period.SetValue( check_period )
|
||||
|
||||
#
|
||||
|
||||
gridbox = wx.FlexGridSizer( 0, 2 )
|
||||
|
||||
gridbox.AddGrowableCol( 1, 1 )
|
||||
|
||||
gridbox.AddF( wx.StaticText( self, label = 'default number of times to check: ' ), CC.FLAGS_MIXED )
|
||||
gridbox.AddF( self._thread_times_to_check, CC.FLAGS_MIXED )
|
||||
gridbox.AddF( wx.StaticText( self, label = 'default wait in seconds between checks: ' ), CC.FLAGS_MIXED )
|
||||
gridbox.AddF( self._thread_check_period, CC.FLAGS_MIXED )
|
||||
|
||||
self.SetSizer( gridbox )
|
||||
|
||||
|
||||
def UpdateOptions( self ):
|
||||
|
||||
HC.options[ 'thread_checker_timings' ] = ( self._thread_times_to_check.GetValue(), self._thread_check_period.GetValue() )
|
||||
|
||||
|
||||
|
||||
def EventOK( self, event ):
|
||||
|
||||
for ( name, page ) in self._listbook.GetNamesToActivePages().items():
|
||||
|
@ -5371,6 +5401,16 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
|
|||
|
||||
all_listbooks = self._service_types_to_listbooks.values()
|
||||
|
||||
for listbook in all_listbooks:
|
||||
|
||||
all_pages = listbook.GetNamesToActivePages().values()
|
||||
|
||||
for page in all_pages:
|
||||
|
||||
page.DoOnOKStuff()
|
||||
|
||||
|
||||
|
||||
for listbook in all_listbooks:
|
||||
|
||||
all_pages = listbook.GetNamesToActivePages().values()
|
||||
|
@ -5514,6 +5554,9 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
|
|||
|
||||
self._original_info = ( service_key, service_type, name, info )
|
||||
|
||||
self._reset_downloading = False
|
||||
self._reset_processing = False
|
||||
|
||||
def InitialiseControls():
|
||||
|
||||
if service_type not in HC.NONEDITABLE_SERVICES:
|
||||
|
@ -5548,8 +5591,11 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
|
|||
|
||||
self._pause_synchronisation = wx.CheckBox( self._repositories_panel, label = 'pause synchronisation' )
|
||||
|
||||
self._reset = wx.Button( self._repositories_panel, label = 'reset cache' )
|
||||
self._reset.Bind( wx.EVT_BUTTON, self.EventServiceReset )
|
||||
self._reset_processing_button = wx.Button( self._repositories_panel, label = 'reset processing cache on dialog ok' )
|
||||
self._reset_processing_button.Bind( wx.EVT_BUTTON, self.EventServiceResetProcessing )
|
||||
|
||||
self._reset_downloading_button = wx.Button( self._repositories_panel, label = 'reset processing and download cache on dialog ok' )
|
||||
self._reset_downloading_button.Bind( wx.EVT_BUTTON, self.EventServiceResetDownload )
|
||||
|
||||
|
||||
if service_type in HC.RATINGS_SERVICES:
|
||||
|
@ -5700,7 +5746,8 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
|
|||
if service_type in HC.REPOSITORIES:
|
||||
|
||||
self._repositories_panel.AddF( self._pause_synchronisation, CC.FLAGS_MIXED )
|
||||
self._repositories_panel.AddF( self._reset, CC.FLAGS_LONE_BUTTON )
|
||||
self._repositories_panel.AddF( self._reset_processing_button, CC.FLAGS_LONE_BUTTON )
|
||||
self._repositories_panel.AddF( self._reset_downloading_button, CC.FLAGS_LONE_BUTTON )
|
||||
|
||||
vbox.AddF( self._repositories_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
@ -5816,6 +5863,20 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
|
|||
else: self._archive_sync_add.Enable()
|
||||
|
||||
|
||||
def DoOnOKStuff( self ):
|
||||
|
||||
( service_key, service_type, name, info ) = self._original_info
|
||||
|
||||
if self._reset_downloading:
|
||||
|
||||
HydrusGlobals.controller.Write( 'reset_service', service_key, delete_updates = True )
|
||||
|
||||
elif self._reset_processing:
|
||||
|
||||
HydrusGlobals.controller.Write( 'reset_service', service_key )
|
||||
|
||||
|
||||
|
||||
def EventArchiveAdd( self, event ):
|
||||
|
||||
if self._archive_sync.GetCount() == 0:
|
||||
|
@ -6047,17 +6108,36 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
|
|||
return ( service_key, service_type, name, info )
|
||||
|
||||
|
||||
def EventServiceReset( self, event ):
|
||||
def EventServiceResetDownload( self, event ):
|
||||
|
||||
( service_key, service_type, name, info ) = self._original_info
|
||||
|
||||
message = 'This will remove all the information for ' + name + ' from the database so it can be reprocessed. It may take several minutes to finish the operation, during which time the gui will likely freeze.' + os.linesep * 2 + 'Once the service is reset, the client will have to reprocess all the information that was deleted, which will take another long time.' + os.linesep * 2 + 'If you do not understand what this button does, you probably want to click no!'
|
||||
message = 'This will completely reset ' + name + ', deleting all downloaded and processed information from the database. It may take several minutes to finish the operation, during which time the gui will likely freeze.' + os.linesep * 2 + 'Once the service is reset, the client will have to redownload and reprocess everything, which could take a very long time.' + os.linesep * 2 + 'If you do not understand what this button does, you definitely want to click no!'
|
||||
|
||||
with ClientGUIDialogs.DialogYesNo( self, message ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_YES:
|
||||
|
||||
with wx.BusyCursor(): HydrusGlobals.controller.Write( 'reset_service', service_key )
|
||||
self._reset_downloading_button.SetLabel( 'everything will be reset on dialog ok!' )
|
||||
|
||||
self._reset_downloading = True
|
||||
|
||||
|
||||
|
||||
|
||||
def EventServiceResetProcessing( self, event ):
|
||||
|
||||
( service_key, service_type, name, info ) = self._original_info
|
||||
|
||||
message = 'This will remove all the processed information for ' + name + ' from the database. It may take several minutes to finish the operation, during which time the gui will likely freeze.' + os.linesep * 2 + 'Once the service is reset, the client will have to reprocess all the downloaded updates, which could take a very long time.' + os.linesep * 2 + 'If you do not understand what this button does, you probably want to click no!'
|
||||
|
||||
with ClientGUIDialogs.DialogYesNo( self, message ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_YES:
|
||||
|
||||
self._reset_processing_button.SetLabel( 'processing will be reset on dialog ok!' )
|
||||
|
||||
self._reset_processing = True
|
||||
|
||||
|
||||
|
||||
|
@ -6410,7 +6490,17 @@ class DialogManageSubscriptions( ClientGUIDialogs.Dialog ):
|
|||
info[ 'frequency_type' ] = 86400
|
||||
info[ 'frequency' ] = 7
|
||||
info[ 'get_tags_if_redundant' ] = False
|
||||
info[ 'initial_limit' ] = 500
|
||||
|
||||
if HC.options[ 'gallery_file_limit' ] is None:
|
||||
|
||||
file_limit = 200
|
||||
|
||||
else:
|
||||
|
||||
file_limit = min( 200, HC.options[ 'gallery_file_limit' ] )
|
||||
|
||||
|
||||
info[ 'initial_limit' ] = file_limit
|
||||
info[ 'advanced_tag_options' ] = {}
|
||||
info[ 'advanced_import_options' ] = ClientDefaults.GetDefaultImportFileOptions()
|
||||
info[ 'last_checked' ] = None
|
||||
|
@ -6582,7 +6672,6 @@ class DialogManageSubscriptions( ClientGUIDialogs.Dialog ):
|
|||
|
||||
def EventResetCache( self, event ):
|
||||
|
||||
|
||||
message = '''Resetting this subscription's cache will delete ''' + HydrusData.ConvertIntToPrettyString( len( self._original_info[ 'url_cache' ] ) ) + ''' remembered links, meaning when the subscription next runs, it will try to download those all over again. This may be expensive in time and data. Only do it if you are willing to wait. Do you want to do it?'''
|
||||
|
||||
with ClientGUIDialogs.DialogYesNo( self, message ) as dlg:
|
||||
|
|
|
@ -85,7 +85,6 @@ class FullscreenHoverFrame( wx.Frame ):
|
|||
( mouse_x, mouse_y ) = wx.GetMousePosition()
|
||||
|
||||
( my_width, my_height ) = self.GetSize()
|
||||
( my_x, my_y ) = self.GetPosition()
|
||||
|
||||
( should_resize, ( my_ideal_width, my_ideal_height ), ( my_ideal_x, my_ideal_y ) ) = self._GetIdealSizeAndPosition()
|
||||
|
||||
|
@ -108,7 +107,11 @@ class FullscreenHoverFrame( wx.Frame ):
|
|||
|
||||
in_position = in_x and in_y
|
||||
|
||||
mouse_over_important_media = ( ClientGUICanvas.ShouldHaveAnimationBar( self._current_media ) or mime in HC.VIDEO or mime == HC.APPLICATION_FLASH ) and self.GetParent().MouseIsOverMedia()
|
||||
mouse_is_over_interactable_media = mime == HC.APPLICATION_FLASH and self.GetParent().MouseIsOverMedia()
|
||||
|
||||
mouse_is_near_animation_bar = self.GetParent().MouseIsNearAnimationBar()
|
||||
|
||||
mouse_is_over_something_important = mouse_is_over_interactable_media or mouse_is_near_animation_bar
|
||||
|
||||
current_focus = wx.Window.FindFocus()
|
||||
|
||||
|
@ -123,7 +126,7 @@ class FullscreenHoverFrame( wx.Frame ):
|
|||
tlp = tlp.GetParent()
|
||||
|
||||
|
||||
ready_to_show = in_position and not mouse_over_important_media and no_dialogs_open and my_parent_in_focus_tree
|
||||
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
|
||||
|
||||
if ready_to_show:
|
||||
|
|
|
@ -1311,7 +1311,10 @@ class ManagementPanelDumper( ManagementPanel ):
|
|||
|
||||
with ClientGUIDialogs.DialogYesNo( self, 'This page is still dumping. Are you sure you want to close it?' ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_NO: raise Exception()
|
||||
if dlg.ShowModal() == wx.ID_NO:
|
||||
|
||||
raise HydrusExceptions.PermissionException()
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1686,7 +1689,10 @@ class ManagementPanelImport( ManagementPanel ):
|
|||
|
||||
with ClientGUIDialogs.DialogYesNo( self, 'This page is still importing. Are you sure you want to close it?' ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_NO: raise Exception()
|
||||
if dlg.ShowModal() == wx.ID_NO:
|
||||
|
||||
raise HydrusExceptions.PermissionException()
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1745,7 +1751,7 @@ class ManagementPanelImports( ManagementPanelImport ):
|
|||
self._get_tags_if_redundant.Hide()
|
||||
|
||||
self._file_limit = ClientGUICommon.NoneableSpinCtrl( self._pending_import_queues_panel, 'file limit', none_phrase = 'no limit', min = 1, max = 1000000 )
|
||||
self._file_limit.SetValue( 500 )
|
||||
self._file_limit.SetValue( HC.options[ 'gallery_file_limit' ] )
|
||||
|
||||
queue_buttons_vbox = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
|
@ -2637,7 +2643,10 @@ class ManagementPanelImportHDD( ManagementPanel ):
|
|||
|
||||
with ClientGUIDialogs.DialogYesNo( self, 'This page is still importing. Are you sure you want to close it?' ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_NO: raise Exception()
|
||||
if dlg.ShowModal() == wx.ID_NO:
|
||||
|
||||
raise HydrusExceptions.PermissionException()
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -3004,7 +3013,10 @@ class ManagementPanelImportThreadWatcher( ManagementPanel ):
|
|||
|
||||
with ClientGUIDialogs.DialogYesNo( self, 'This page is still importing. Are you sure you want to close it?' ) as dlg:
|
||||
|
||||
if dlg.ShowModal() == wx.ID_NO: raise Exception()
|
||||
if dlg.ShowModal() == wx.ID_NO:
|
||||
|
||||
raise HydrusExceptions.PermissionException()
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -157,7 +157,10 @@ class Page( wx.SplitterWindow ):
|
|||
|
||||
|
||||
|
||||
def TestAbleToClose( self ): self._management_panel.TestAbleToClose()
|
||||
def TestAbleToClose( self ):
|
||||
|
||||
self._management_panel.TestAbleToClose()
|
||||
|
||||
|
||||
class GUISession( HydrusSerialisable.SerialisableBaseNamed ):
|
||||
|
||||
|
|
|
@ -240,7 +240,7 @@ class GalleryQuery( HydrusSerialisable.SerialisableBase ):
|
|||
self._query_type = None
|
||||
self._query = None
|
||||
self._get_tags_if_redundant = False
|
||||
self._file_limit = 500
|
||||
self._file_limit = HC.options[ 'gallery_file_limit' ]
|
||||
self._paused = False
|
||||
self._page_index = 0
|
||||
self._url_cache = None
|
||||
|
@ -718,7 +718,7 @@ class Subscription( HydrusSerialisable.SerialisableBaseNamed ):
|
|||
self._query_type = None
|
||||
self._query = None
|
||||
self._get_tags_if_redundant = False
|
||||
self._file_limit = 500
|
||||
self._file_limit = HC.options[ 'gallery_file_limit' ]
|
||||
self._periodic = None
|
||||
self._page_index = 0
|
||||
self._url_cache = None
|
||||
|
|
|
@ -37,7 +37,7 @@ options = {}
|
|||
# Misc
|
||||
|
||||
NETWORK_VERSION = 17
|
||||
SOFTWARE_VERSION = 171
|
||||
SOFTWARE_VERSION = 172
|
||||
|
||||
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )
|
||||
|
||||
|
@ -92,6 +92,10 @@ IMPORT_FOLDER_TYPE_SYNCHRONISE = 1
|
|||
EXPORT_FOLDER_TYPE_REGULAR = 0
|
||||
EXPORT_FOLDER_TYPE_SYNCHRONISE = 1
|
||||
|
||||
HYDRUS_CLIENT = 0
|
||||
HYDRUS_SERVER = 1
|
||||
HYDRUS_TEST = 2
|
||||
|
||||
GET_DATA = 0
|
||||
POST_DATA = 1
|
||||
POST_PETITIONS = 2
|
||||
|
|
|
@ -13,13 +13,38 @@ import sys
|
|||
import threading
|
||||
import time
|
||||
import traceback
|
||||
import wx
|
||||
|
||||
class HydrusController( wx.App ):
|
||||
class HydrusController( object ):
|
||||
|
||||
db_class = HydrusDB.HydrusDB
|
||||
pubsub_binding_errors_to_ignore = []
|
||||
|
||||
def __init__( self ):
|
||||
|
||||
HydrusGlobals.controller = self
|
||||
|
||||
self._pubsub = HydrusPubSub.HydrusPubSub( self, self.pubsub_binding_errors_to_ignore )
|
||||
|
||||
self._currently_doing_pubsub = False
|
||||
|
||||
self._daemons = []
|
||||
self._caches = {}
|
||||
self._managers = {}
|
||||
|
||||
self._call_to_threads = [ HydrusThreading.DAEMONCallToThread( self ) for i in range( 10 ) ]
|
||||
|
||||
self._timestamps = collections.defaultdict( lambda: 0 )
|
||||
|
||||
self._timestamps[ 'boot' ] = HydrusData.GetNow()
|
||||
|
||||
self._just_woke_from_sleep = False
|
||||
self._system_busy = False
|
||||
|
||||
|
||||
def _InitDB( self ):
|
||||
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def _Read( self, action, *args, **kwargs ):
|
||||
|
||||
result = self._db.Read( action, HC.HIGH_PRIORITY, *args, **kwargs )
|
||||
|
@ -71,8 +96,6 @@ class HydrusController( wx.App ):
|
|||
|
||||
def GetCache( self, name ): return self._caches[ name ]
|
||||
|
||||
def GetDB( self ): return self._db
|
||||
|
||||
def GetManager( self, name ): return self._managers[ name ]
|
||||
|
||||
def GoodTimeToDoBackgroundWork( self ):
|
||||
|
@ -87,45 +110,23 @@ class HydrusController( wx.App ):
|
|||
return self._just_woke_from_sleep
|
||||
|
||||
|
||||
def InitDaemons( self ):
|
||||
def InitModel( self ):
|
||||
|
||||
self._db = self._InitDB()
|
||||
|
||||
threading.Thread( target = self._db.MainLoop, name = 'Database Main Loop' ).start()
|
||||
|
||||
|
||||
def InitView( self ):
|
||||
|
||||
self._daemons.append( HydrusThreading.DAEMONWorker( self, 'SleepCheck', HydrusDaemons.DAEMONSleepCheck, period = 120 ) )
|
||||
self._daemons.append( HydrusThreading.DAEMONWorker( self, 'MaintainDB', HydrusDaemons.DAEMONMaintainDB, period = 300 ) )
|
||||
self._daemons.append( HydrusThreading.DAEMONWorker( self, 'MaintainMemory', HydrusDaemons.DAEMONMaintainMemory, period = 300 ) )
|
||||
|
||||
|
||||
def InitData( self ):
|
||||
|
||||
self.SetAssertMode( wx.PYAPP_ASSERT_SUPPRESS )
|
||||
|
||||
HydrusGlobals.controller = self
|
||||
self._pubsub = HydrusPubSub.HydrusPubSub( self, self.pubsub_binding_errors_to_ignore )
|
||||
self._currently_doing_pubsub = False
|
||||
|
||||
self._daemons = []
|
||||
self._caches = {}
|
||||
self._managers = {}
|
||||
|
||||
self._call_to_threads = [ HydrusThreading.DAEMONCallToThread( self ) for i in range( 10 ) ]
|
||||
|
||||
self._timestamps = collections.defaultdict( lambda: 0 )
|
||||
|
||||
self._timestamps[ 'boot' ] = HydrusData.GetNow()
|
||||
|
||||
self._just_woke_from_sleep = False
|
||||
self._system_busy = False
|
||||
|
||||
|
||||
def InitDB( self ):
|
||||
|
||||
self._db = self.db_class( self )
|
||||
|
||||
threading.Thread( target = self._db.MainLoop, name = 'Database Main Loop' ).start()
|
||||
|
||||
|
||||
def MaintainDB( self ):
|
||||
|
||||
raise NotImplementedError()
|
||||
pass
|
||||
|
||||
|
||||
def MaintainMemory( self ):
|
||||
|
@ -151,13 +152,25 @@ class HydrusController( wx.App ):
|
|||
|
||||
def Read( self, action, *args, **kwargs ): return self._Read( action, *args, **kwargs )
|
||||
|
||||
def ShutdownDB( self ):
|
||||
def ShutdownModel( self ):
|
||||
|
||||
self._db.Shutdown()
|
||||
HydrusGlobals.model_shutdown = True
|
||||
|
||||
while not self._db.LoopIsFinished(): time.sleep( 0.1 )
|
||||
|
||||
|
||||
def ShutdownView( self ):
|
||||
|
||||
HydrusGlobals.view_shutdown = True
|
||||
|
||||
self.pub( 'wake_daemons' )
|
||||
|
||||
while True in ( daemon.is_alive() for daemon in self._daemons ):
|
||||
|
||||
time.sleep( 0.1 )
|
||||
|
||||
|
||||
|
||||
def SleepCheck( self ):
|
||||
|
||||
if HydrusData.TimeHasPassed( self._timestamps[ 'now_awake' ] ):
|
||||
|
@ -195,7 +208,7 @@ class HydrusController( wx.App ):
|
|||
|
||||
while True:
|
||||
|
||||
if HydrusGlobals.view_shutdown: raise Exception( 'Application shutting down!' )
|
||||
if HydrusGlobals.view_shutdown: raise HydrusExceptions.ShutdownException( 'Application shutting down!' )
|
||||
elif self._pubsub.NoJobsQueued() and not self._currently_doing_pubsub: return
|
||||
else: time.sleep( 0.00001 )
|
||||
|
||||
|
|
|
@ -235,7 +235,7 @@ class HydrusDB( object ):
|
|||
|
||||
try:
|
||||
|
||||
( priority, job ) = self._jobs.get( timeout = 1 )
|
||||
( priority, job ) = self._jobs.get( timeout = 0.1 )
|
||||
|
||||
self._currently_doing_job = True
|
||||
|
||||
|
|
|
@ -578,63 +578,43 @@ def IntelligentMassIntersect( sets_to_reduce ):
|
|||
if answer is None: return set()
|
||||
else: return answer
|
||||
|
||||
def IsAlreadyRunning():
|
||||
def IsAlreadyRunning( instance ):
|
||||
|
||||
try:
|
||||
|
||||
me = psutil.Process()
|
||||
|
||||
my_pid = me.pid
|
||||
my_exe = me.exe()
|
||||
my_cmd = me.cmdline()
|
||||
|
||||
except psutil.Error:
|
||||
|
||||
return False
|
||||
|
||||
path = HC.BASE_DIR + os.path.sep + instance + '_running'
|
||||
|
||||
for p in psutil.process_iter():
|
||||
if os.path.exists( path ):
|
||||
|
||||
try:
|
||||
with open( path, 'rb' ) as f:
|
||||
|
||||
if not p.is_running():
|
||||
result = f.read()
|
||||
|
||||
try:
|
||||
|
||||
continue
|
||||
( pid, create_time ) = result.split( os.linesep )
|
||||
|
||||
pid = int( pid )
|
||||
create_time = float( create_time )
|
||||
|
||||
except ValueError:
|
||||
|
||||
return False
|
||||
|
||||
|
||||
# this is to skip the linux PyInstaller loader
|
||||
is_my_parent = False
|
||||
|
||||
for c in p.children():
|
||||
try:
|
||||
|
||||
if c.pid == my_pid:
|
||||
if psutil.pid_exists( pid ):
|
||||
|
||||
is_my_parent = True
|
||||
p = psutil.Process( pid )
|
||||
|
||||
break
|
||||
if p.create_time() == create_time and p.is_running():
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
if is_my_parent:
|
||||
except psutil.Error:
|
||||
|
||||
continue
|
||||
|
||||
|
||||
p_pid = p.pid
|
||||
p_exe = p.exe()
|
||||
p_cmd = p.cmdline()
|
||||
|
||||
except psutil.Error:
|
||||
|
||||
continue
|
||||
|
||||
|
||||
if p_pid != my_pid:
|
||||
|
||||
if p_exe == my_exe and p_cmd == my_cmd:
|
||||
|
||||
print( p.children( recursive = True ) )
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
@ -662,6 +642,30 @@ def ReadFileLikeAsBlocks( f, block_size ):
|
|||
|
||||
next_block = f.read( block_size )
|
||||
|
||||
def RecordRunningStart( instance ):
|
||||
|
||||
path = HC.BASE_DIR + os.path.sep + instance + '_running'
|
||||
|
||||
record_string = ''
|
||||
|
||||
try:
|
||||
|
||||
me = psutil.Process()
|
||||
|
||||
record_string += str( me.pid )
|
||||
record_string += os.linesep
|
||||
record_string += str( me.create_time() )
|
||||
|
||||
except psutil.Error:
|
||||
|
||||
return
|
||||
|
||||
|
||||
with open( path, 'wb' ) as f:
|
||||
|
||||
f.write( record_string )
|
||||
|
||||
|
||||
def ShowExceptionDefault( e ):
|
||||
|
||||
etype = type( e )
|
||||
|
@ -1249,7 +1253,7 @@ class JobDatabase( object ):
|
|||
while True:
|
||||
|
||||
if self._result_ready.wait( 5 ) == True: break
|
||||
elif HydrusGlobals.model_shutdown: raise Exception( 'Application quit before db could serve result!' )
|
||||
elif HydrusGlobals.model_shutdown: raise HydrusExceptions.ShutdownException( 'Application quit before db could serve result!' )
|
||||
|
||||
|
||||
if isinstance( self._result, HydrusExceptions.DBException ):
|
||||
|
|
|
@ -2,6 +2,8 @@ controller = None
|
|||
view_shutdown = False
|
||||
model_shutdown = False
|
||||
|
||||
instance = None
|
||||
|
||||
is_first_start = False
|
||||
is_db_updated = False
|
||||
|
||||
|
|
|
@ -537,8 +537,9 @@ class HTTPConnection( object ):
|
|||
|
||||
# some booru is giving daft redirect responses
|
||||
print( url )
|
||||
url = urllib.quote( url, safe = '/?=&' )
|
||||
url = urllib.quote( url.encode( 'utf-8' ), safe = '/?=&' )
|
||||
print( url )
|
||||
|
||||
|
||||
if not url.startswith( self._scheme ):
|
||||
|
||||
|
|
|
@ -290,6 +290,7 @@ class HydrusServiceRepository( HydrusServiceRestricted ):
|
|||
root.putChild( 'num_petitions', HydrusServerResources.HydrusResourceCommandRestrictedNumPetitions( self._service_key, self._service_type, REMOTE_DOMAIN ) )
|
||||
root.putChild( 'petition', HydrusServerResources.HydrusResourceCommandRestrictedPetition( self._service_key, self._service_type, REMOTE_DOMAIN ) )
|
||||
root.putChild( 'content_update_package', HydrusServerResources.HydrusResourceCommandRestrictedContentUpdate( self._service_key, self._service_type, REMOTE_DOMAIN ) )
|
||||
root.putChild( 'immediate_content_update_package', HydrusServerResources.HydrusResourceCommandRestrictedImmediateContentUpdate( self._service_key, self._service_type, REMOTE_DOMAIN ) )
|
||||
root.putChild( 'service_update_package', HydrusServerResources.HydrusResourceCommandRestrictedServiceUpdate( self._service_key, self._service_type, REMOTE_DOMAIN ) )
|
||||
|
||||
return root
|
||||
|
|
|
@ -3,6 +3,7 @@ import HydrusConstants as HC
|
|||
import HydrusExceptions
|
||||
import HydrusFileHandling
|
||||
import HydrusImageHandling
|
||||
import HydrusSerialisable
|
||||
import HydrusThreading
|
||||
import os
|
||||
import ServerFiles
|
||||
|
@ -1018,6 +1019,21 @@ class HydrusResourceCommandRestrictedContentUpdate( HydrusResourceCommandRestric
|
|||
return response_context
|
||||
|
||||
|
||||
class HydrusResourceCommandRestrictedImmediateContentUpdate( HydrusResourceCommandRestricted ):
|
||||
|
||||
GET_PERMISSION = HC.RESOLVE_PETITIONS
|
||||
|
||||
def _threadDoGETJob( self, request ):
|
||||
|
||||
content_update = HydrusGlobals.controller.Read( 'immediate_content_update', self._service_key )
|
||||
|
||||
network_string = HydrusSerialisable.DumpToNetworkString( content_update )
|
||||
|
||||
response_context = ResponseContext( 200, mime = HC.APPLICATION_JSON, body = network_string )
|
||||
|
||||
return response_context
|
||||
|
||||
|
||||
class HydrusResourceCommandRestrictedServiceUpdate( HydrusResourceCommandRestricted ):
|
||||
|
||||
GET_PERMISSION = HC.GET_DATA
|
||||
|
|
|
@ -17,15 +17,9 @@ class DAEMON( threading.Thread ):
|
|||
|
||||
self._event = threading.Event()
|
||||
|
||||
self._controller.sub( self, 'shutdown', 'shutdown' )
|
||||
self._controller.sub( self, 'wake', 'wake_daemons' )
|
||||
|
||||
|
||||
def shutdown( self ):
|
||||
|
||||
self._event.set()
|
||||
|
||||
|
||||
def wake( self ):
|
||||
|
||||
self._event.set()
|
||||
|
|
|
@ -2,37 +2,116 @@ import httplib
|
|||
import HydrusConstants as HC
|
||||
import HydrusController
|
||||
import HydrusData
|
||||
import HydrusExceptions
|
||||
import HydrusGlobals
|
||||
import HydrusNetworking
|
||||
import HydrusServer
|
||||
import HydrusSessions
|
||||
import HydrusThreading
|
||||
import os
|
||||
import ServerDaemons
|
||||
import ServerDB
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
import wx
|
||||
from twisted.internet import reactor
|
||||
from twisted.internet import defer
|
||||
|
||||
ID_MAINTENANCE_EVENT_TIMER = wx.NewId()
|
||||
|
||||
MAINTENANCE_PERIOD = 5 * 60
|
||||
|
||||
def GetStartingAction():
|
||||
|
||||
action = None
|
||||
|
||||
args = sys.argv[1:]
|
||||
|
||||
if len( args ) > 0:
|
||||
|
||||
command = args[0]
|
||||
|
||||
while command.startswith( '-' ):
|
||||
|
||||
command = command[ 1: ]
|
||||
|
||||
|
||||
if command == 'help':
|
||||
|
||||
action = 'help'
|
||||
|
||||
else:
|
||||
|
||||
already_running = HydrusData.IsAlreadyRunning( 'server' )
|
||||
|
||||
if command == 'start':
|
||||
|
||||
if already_running:
|
||||
|
||||
raise HydrusExceptions.PermissionException( 'The server is already running!' )
|
||||
|
||||
else:
|
||||
|
||||
action = None
|
||||
|
||||
|
||||
elif command == 'stop':
|
||||
|
||||
if already_running:
|
||||
|
||||
action = 'stop'
|
||||
|
||||
else:
|
||||
|
||||
raise HydrusExceptions.PermissionException( 'The server is not running, so it cannot be stopped!' )
|
||||
|
||||
|
||||
elif command == 'restart':
|
||||
|
||||
if already_running:
|
||||
|
||||
action = 'restart'
|
||||
|
||||
else:
|
||||
|
||||
action = 'start'
|
||||
|
||||
|
||||
|
||||
|
||||
else:
|
||||
|
||||
already_running = HydrusData.IsAlreadyRunning( 'server' )
|
||||
|
||||
if not already_running:
|
||||
|
||||
action = 'start'
|
||||
|
||||
else:
|
||||
|
||||
print( 'The server is already running. Would you like to [s]top it, or [r]estart it?' )
|
||||
|
||||
answer = raw_input()
|
||||
|
||||
if len( answer ) > 0:
|
||||
|
||||
answer = answer[0]
|
||||
|
||||
if answer == 's':
|
||||
|
||||
action = 'stop'
|
||||
|
||||
elif answer == 'r':
|
||||
|
||||
action = 'restart'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return action
|
||||
|
||||
class Controller( HydrusController.HydrusController ):
|
||||
|
||||
db_class = ServerDB.DB
|
||||
|
||||
def _AlreadyRunning( self, port ):
|
||||
def _InitDB( self ):
|
||||
|
||||
try:
|
||||
|
||||
connection = HydrusNetworking.GetLocalConnection( port )
|
||||
connection.close()
|
||||
|
||||
return True
|
||||
|
||||
except: return False
|
||||
return ServerDB.DB( self )
|
||||
|
||||
|
||||
def ActionService( self, service_key, action ):
|
||||
|
@ -93,23 +172,55 @@ class Controller( HydrusController.HydrusController ):
|
|||
elif action == 'stop': del self._services[ service_key ]
|
||||
|
||||
|
||||
|
||||
|
||||
reactor.callFromThread( TWISTEDDoIt )
|
||||
|
||||
|
||||
def EventExit( self, event ):
|
||||
def CheckIfAdminPortInUse( self ):
|
||||
|
||||
wx.CallAfter( self._tbicon.Destroy )
|
||||
( service_type, options ) = self.Read( 'service_info', HC.SERVER_ADMIN_KEY )
|
||||
|
||||
self.ShutdownDB()
|
||||
port = options[ 'port' ]
|
||||
|
||||
already_bound = False
|
||||
|
||||
try:
|
||||
|
||||
connection = HydrusNetworking.GetLocalConnection( port )
|
||||
connection.close()
|
||||
|
||||
already_bound = True
|
||||
|
||||
except: pass
|
||||
|
||||
if already_bound:
|
||||
|
||||
raise HydrusExceptions.PermissionException( 'Something was already bound to port ' + HydrusData.ToString( port ) )
|
||||
|
||||
|
||||
|
||||
def GetManager( self, manager_type ): return self._managers[ manager_type ]
|
||||
|
||||
def InitDaemons( self ):
|
||||
def Exit( self ):
|
||||
|
||||
HydrusController.HydrusController.InitDaemons( self )
|
||||
self.ShutdownView()
|
||||
|
||||
self.ShutdownModel()
|
||||
|
||||
|
||||
def InitModel( self ):
|
||||
|
||||
HydrusController.HydrusController.InitModel( self )
|
||||
|
||||
self._managers[ 'restricted_services_sessions' ] = HydrusSessions.HydrusSessionManagerServer()
|
||||
self._managers[ 'messaging_sessions' ] = HydrusSessions.HydrusMessagingSessionManagerServer()
|
||||
|
||||
self._services = {}
|
||||
|
||||
self.sub( self, 'ActionService', 'action_service' )
|
||||
|
||||
|
||||
def InitView( self ):
|
||||
|
||||
HydrusController.HydrusController.InitView( self )
|
||||
|
||||
self._daemons.append( HydrusThreading.DAEMONQueue( self, 'FlushRequestsMade', ServerDaemons.DAEMONFlushRequestsMade, 'request_made', period = 60 ) )
|
||||
|
||||
|
@ -120,110 +231,48 @@ class Controller( HydrusController.HydrusController ):
|
|||
self._daemons.append( HydrusThreading.DAEMONWorker( self, 'CheckDataUsage', ServerDaemons.DAEMONCheckDataUsage, period = 86400 ) )
|
||||
self._daemons.append( HydrusThreading.DAEMONWorker( self, 'UPnP', ServerDaemons.DAEMONUPnP, ( 'notify_new_options', ), period = 43200 ) )
|
||||
|
||||
self.CheckIfAdminPortInUse()
|
||||
|
||||
service_keys = self.Read( 'service_keys' )
|
||||
|
||||
for service_key in service_keys: self.ActionService( service_key, 'start' )
|
||||
|
||||
|
||||
def JustWokeFromSleep( self ): return False
|
||||
|
||||
def MaintainDB( self ):
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def NotifyPubSubs( self ):
|
||||
|
||||
self.CallToThread( self.ProcessPubSub )
|
||||
|
||||
|
||||
def OnInit( self ):
|
||||
def Run( self, action ):
|
||||
|
||||
try:
|
||||
if action in ( 'stop', 'restart' ):
|
||||
|
||||
self.InitData()
|
||||
raise HydrusExceptions.PermissionException( 'This isn\'t working yet! You will have to Ctrl+C to quit an existing server for now!' )
|
||||
|
||||
if HydrusData.IsAlreadyRunning():
|
||||
|
||||
raise Exception( 'It looks like this server is already running!' )
|
||||
|
||||
|
||||
self.InitDB()
|
||||
|
||||
self.Bind( wx.EVT_MENU, self.EventExit, id=wx.ID_EXIT )
|
||||
|
||||
self._managers[ 'restricted_services_sessions' ] = HydrusSessions.HydrusSessionManagerServer()
|
||||
self._managers[ 'messaging_sessions' ] = HydrusSessions.HydrusMessagingSessionManagerServer()
|
||||
|
||||
self.sub( self, 'ActionService', 'action_service' )
|
||||
|
||||
self._services = {}
|
||||
|
||||
#
|
||||
|
||||
( service_type, options ) = self.Read( 'service_info', HC.SERVER_ADMIN_KEY )
|
||||
|
||||
port = options[ 'port' ]
|
||||
|
||||
try:
|
||||
|
||||
connection = HydrusNetworking.GetLocalConnection( port )
|
||||
connection.close()
|
||||
|
||||
message = 'Something was already bound to port ' + HydrusData.ToString( port )
|
||||
|
||||
wx.MessageBox( message )
|
||||
|
||||
return False
|
||||
|
||||
except: pass
|
||||
|
||||
#
|
||||
|
||||
service_keys = self.Read( 'service_keys' )
|
||||
|
||||
for service_key in service_keys: self.ActionService( service_key, 'start' )
|
||||
|
||||
self.InitDaemons()
|
||||
|
||||
if HC.PLATFORM_WINDOWS: self._tbicon = TaskBarIcon()
|
||||
else:
|
||||
|
||||
stay_open_frame = wx.Frame( None, title = 'Hydrus Server' )
|
||||
|
||||
stay_open_frame.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
||||
|
||||
stay_open_frame.SetIcon( wx.Icon( HC.STATIC_DIR + os.path.sep + 'hydrus.ico', wx.BITMAP_TYPE_ICO ) )
|
||||
|
||||
wx.StaticText( stay_open_frame, label = 'The hydrus server is now running.' + os.linesep * 2 + 'Close this window to stop it.' )
|
||||
|
||||
( x, y ) = stay_open_frame.GetEffectiveMinSize()
|
||||
|
||||
stay_open_frame.SetInitialSize( ( x, y ) )
|
||||
|
||||
stay_open_frame.Show()
|
||||
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
|
||||
print( traceback.format_exc() )
|
||||
|
||||
return False
|
||||
self.ShutdownSiblingInstance()
|
||||
|
||||
|
||||
|
||||
class TaskBarIcon( wx.TaskBarIcon ):
|
||||
|
||||
def __init__( self ):
|
||||
|
||||
wx.TaskBarIcon.__init__( self )
|
||||
|
||||
icon = wx.Icon( HC.STATIC_DIR + os.path.sep + 'hydrus.ico', wx.BITMAP_TYPE_ICO )
|
||||
|
||||
self.SetIcon( icon, 'hydrus server' )
|
||||
|
||||
self._tbmenu = wx.Menu()
|
||||
|
||||
self._tbmenu.Append( wx.ID_EXIT, 'exit' )
|
||||
|
||||
self.Bind( wx.EVT_TASKBAR_RIGHT_DOWN, lambda event: self.PopupMenu( self._tbmenu ) )
|
||||
if action in ( 'start', 'restart' ):
|
||||
|
||||
HydrusData.RecordRunningStart( 'server' )
|
||||
|
||||
self.InitModel()
|
||||
|
||||
self.InitView()
|
||||
|
||||
while not HydrusGlobals.model_shutdown:
|
||||
|
||||
try:
|
||||
|
||||
time.sleep( 1 )
|
||||
|
||||
except KeyboardInterrupt:
|
||||
|
||||
self.Exit()
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -799,6 +799,53 @@ class DB( HydrusDB.HydrusDB ):
|
|||
return [ registration_key for ( registration_key, account_key, access_key ) in keys ]
|
||||
|
||||
|
||||
def _GenerateImmediateContentUpdate( self, service_key ):
|
||||
|
||||
update_ends = self._GetUpdateEnds()
|
||||
|
||||
latest_end = update_ends[ service_key ]
|
||||
|
||||
begin = latest_end + 1
|
||||
|
||||
end = HydrusData.GetNow()
|
||||
|
||||
service_id = self._GetServiceId( service_key )
|
||||
|
||||
service_type = self._GetServiceType( service_id )
|
||||
|
||||
if service_type == HC.FILE_REPOSITORY:
|
||||
|
||||
iterator = self._IterateFileUpdateContentData
|
||||
|
||||
elif service_type == HC.TAG_REPOSITORY:
|
||||
|
||||
iterator = self._IterateTagUpdateContentData
|
||||
|
||||
|
||||
subindex = 0
|
||||
weight = 0
|
||||
|
||||
content_update_package = HydrusData.ServerToClientContentUpdatePackage()
|
||||
|
||||
smaller_time_step = max( 10, ( end - begin ) / 100 )
|
||||
|
||||
sub_begin = begin
|
||||
|
||||
while sub_begin <= end:
|
||||
|
||||
sub_end = min( ( sub_begin + smaller_time_step ) - 1, end )
|
||||
|
||||
for ( data_type, action, rows, hash_ids_to_hashes, rows_weight ) in iterator( service_id, sub_begin, sub_end ):
|
||||
|
||||
content_update_package.AddContentData( data_type, action, rows, hash_ids_to_hashes )
|
||||
|
||||
|
||||
sub_begin += smaller_time_step
|
||||
|
||||
|
||||
return content_update_package
|
||||
|
||||
|
||||
def _GenerateUpdate( self, service_key, begin, end ):
|
||||
|
||||
service_id = self._GetServiceId( service_key )
|
||||
|
@ -2060,6 +2107,7 @@ class DB( HydrusDB.HydrusDB ):
|
|||
elif action == 'account_key_from_identifier': result = self._GetAccountKeyFromIdentifier( *args, **kwargs )
|
||||
elif action == 'account_types': result = self._GetAccountTypes( *args, **kwargs )
|
||||
elif action == 'dirty_updates': result = self._GetDirtyUpdates( *args, **kwargs )
|
||||
elif action == 'immediate_content_update': result = self._GenerateImmediateContentUpdate( *args, **kwargs )
|
||||
elif action == 'init': result = self._InitAdmin( *args, **kwargs )
|
||||
elif action == 'ip': result = self._GetIPTimestamp( *args, **kwargs )
|
||||
elif action == 'messaging_sessions': result = self._GetMessagingSessions( *args, **kwargs )
|
||||
|
|
|
@ -33,36 +33,61 @@ def DAEMONFlushRequestsMade( all_requests ): HydrusGlobals.controller.WriteSynch
|
|||
|
||||
def DAEMONGenerateUpdates():
|
||||
|
||||
dirty_updates = HydrusGlobals.controller.Read( 'dirty_updates' )
|
||||
|
||||
for ( service_key, tuples ) in dirty_updates.items():
|
||||
if not HydrusGlobals.server_busy:
|
||||
|
||||
for ( begin, end ) in tuples:
|
||||
dirty_updates = HydrusGlobals.controller.Read( 'dirty_updates' )
|
||||
|
||||
for ( service_key, tuples ) in dirty_updates.items():
|
||||
|
||||
HydrusGlobals.controller.WriteSynchronous( 'clean_update', service_key, begin, end )
|
||||
for ( begin, end ) in tuples:
|
||||
|
||||
if HydrusGlobals.view_shutdown:
|
||||
|
||||
return
|
||||
|
||||
|
||||
HydrusGlobals.server_busy = True
|
||||
|
||||
HydrusGlobals.controller.WriteSynchronous( 'clean_update', service_key, begin, end )
|
||||
|
||||
HydrusGlobals.server_busy = False
|
||||
|
||||
time.sleep( 1 )
|
||||
|
||||
|
||||
|
||||
|
||||
update_ends = HydrusGlobals.controller.Read( 'update_ends' )
|
||||
|
||||
for ( service_key, biggest_end ) in update_ends.items():
|
||||
update_ends = HydrusGlobals.controller.Read( 'update_ends' )
|
||||
|
||||
now = HydrusData.GetNow()
|
||||
|
||||
next_begin = biggest_end + 1
|
||||
next_end = biggest_end + HC.UPDATE_DURATION
|
||||
|
||||
while next_end < now:
|
||||
for ( service_key, biggest_end ) in update_ends.items():
|
||||
|
||||
HydrusGlobals.controller.WriteSynchronous( 'create_update', service_key, next_begin, next_end )
|
||||
|
||||
biggest_end = next_end
|
||||
if HydrusGlobals.view_shutdown:
|
||||
|
||||
return
|
||||
|
||||
|
||||
now = HydrusData.GetNow()
|
||||
|
||||
next_begin = biggest_end + 1
|
||||
next_end = biggest_end + HC.UPDATE_DURATION
|
||||
|
||||
HydrusGlobals.server_busy = True
|
||||
|
||||
while next_end < now:
|
||||
|
||||
HydrusGlobals.controller.WriteSynchronous( 'create_update', service_key, next_begin, next_end )
|
||||
|
||||
biggest_end = next_end
|
||||
|
||||
now = HydrusData.GetNow()
|
||||
|
||||
next_begin = biggest_end + 1
|
||||
next_end = biggest_end + HC.UPDATE_DURATION
|
||||
|
||||
|
||||
HydrusGlobals.server_busy = False
|
||||
|
||||
time.sleep( 1 )
|
||||
|
||||
|
||||
|
||||
def DAEMONUPnP():
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
# 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
|
||||
# To Public License, Version 2, as published by Sam Hocevar. See
|
||||
# http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
try:
|
||||
|
||||
import locale
|
||||
|
||||
try: locale.setlocale( locale.LC_ALL, '' )
|
||||
except: pass
|
||||
|
||||
from include import HydrusConstants as HC
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from include import ServerController
|
||||
import threading
|
||||
from twisted.internet import reactor
|
||||
from include import HydrusExceptions
|
||||
from include import HydrusGlobals
|
||||
import traceback
|
||||
|
||||
HydrusGlobals.instance = HC.HYDRUS_SERVER
|
||||
|
||||
action = ServerController.GetStartingAction()
|
||||
|
||||
if action is None or action == 'help':
|
||||
|
||||
print( 'This is the hydrus server. It accepts these commands:' )
|
||||
print( '' )
|
||||
print( 'server start - runs the server' )
|
||||
print( 'server stop - stops an already running server' )
|
||||
print( 'server restart - stops an already running server, then runs itself' )
|
||||
print( '' )
|
||||
print( 'You can also run \'server\' without arguments. Depending on what is going on, it will try to start or it will ask you if you want to stop or restart.' )
|
||||
print( 'You can also stop the server just by hitting your keyboard interrupt (usually Ctrl+C).')
|
||||
print( '' )
|
||||
print( 'PROTIP: stop and restart don\'t work yet lol')
|
||||
|
||||
else:
|
||||
|
||||
if action in ( 'start', 'restart' ):
|
||||
|
||||
print( 'Running...' )
|
||||
|
||||
|
||||
error_occured = False
|
||||
|
||||
initial_sys_stdout = sys.stdout
|
||||
initial_sys_stderr = sys.stderr
|
||||
|
||||
with open( HC.LOGS_DIR + os.path.sep + 'server.log', 'a' ) as f:
|
||||
|
||||
sys.stdout = f
|
||||
sys.stderr = f
|
||||
|
||||
try:
|
||||
|
||||
print( 'hydrus server started at ' + time.ctime() )
|
||||
|
||||
threading.Thread( target = reactor.run, kwargs = { 'installSignalHandlers' : 0 } ).start()
|
||||
|
||||
controller = ServerController.Controller()
|
||||
|
||||
controller.Run( action )
|
||||
|
||||
except HydrusExceptions.PermissionException as e:
|
||||
|
||||
error_occured = True
|
||||
error = str( e )
|
||||
|
||||
print( error )
|
||||
|
||||
except:
|
||||
|
||||
error_occured = True
|
||||
error = traceback.format_exc()
|
||||
|
||||
print( 'hydrus server failed at ' + time.ctime() )
|
||||
|
||||
print( traceback.format_exc() )
|
||||
|
||||
finally:
|
||||
|
||||
HydrusGlobals.view_shutdown = True
|
||||
HydrusGlobals.model_shutdown = True
|
||||
|
||||
try: controller.pubimmediate( 'wake_daemons' )
|
||||
except: pass
|
||||
|
||||
reactor.callFromThread( reactor.stop )
|
||||
|
||||
print( 'hydrus server shut down at ' + time.ctime() )
|
||||
|
||||
|
||||
|
||||
sys.stdout = initial_sys_stdout
|
||||
sys.stderr = initial_sys_stderr
|
||||
|
||||
if error_occured:
|
||||
|
||||
print( error )
|
||||
|
||||
|
||||
if action in ( 'start', 'restart' ):
|
||||
|
||||
print( 'Finished.' )
|
||||
|
||||
|
||||
|
||||
except HydrusExceptions.PermissionException as e:
|
||||
|
||||
print( e )
|
||||
|
||||
except:
|
||||
|
||||
import traceback
|
||||
|
||||
print( 'Critical error occured! Details written to crash.log!' )
|
||||
|
||||
with open( 'crash.log', 'wb' ) as f: f.write( traceback.format_exc() )
|
||||
|
73
server.pyw
73
server.pyw
|
@ -1,73 +0,0 @@
|
|||
# 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
|
||||
# To Public License, Version 2, as published by Sam Hocevar. See
|
||||
# http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
try:
|
||||
|
||||
import locale
|
||||
|
||||
try: locale.setlocale( locale.LC_ALL, '' )
|
||||
except: pass
|
||||
|
||||
from include import HydrusConstants as HC
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from include import ServerController
|
||||
import threading
|
||||
from twisted.internet import reactor
|
||||
from include import HydrusGlobals
|
||||
|
||||
initial_sys_stdout = sys.stdout
|
||||
initial_sys_stderr = sys.stderr
|
||||
|
||||
with open( HC.LOGS_DIR + os.path.sep + 'server.log', 'a' ) as f:
|
||||
|
||||
sys.stdout = f
|
||||
sys.stderr = f
|
||||
|
||||
try:
|
||||
|
||||
print( 'hydrus server started at ' + time.ctime() )
|
||||
|
||||
threading.Thread( target = reactor.run, kwargs = { 'installSignalHandlers' : 0 } ).start()
|
||||
|
||||
app = ServerController.Controller()
|
||||
|
||||
app.MainLoop()
|
||||
|
||||
except:
|
||||
|
||||
print( 'hydrus server failed at ' + time.ctime() )
|
||||
|
||||
import traceback
|
||||
print( traceback.format_exc() )
|
||||
|
||||
finally:
|
||||
|
||||
HydrusGlobals.view_shutdown = True
|
||||
HydrusGlobals.model_shutdown = True
|
||||
|
||||
app.pubimmediate( 'shutdown' )
|
||||
|
||||
reactor.callFromThread( reactor.stop )
|
||||
|
||||
print( 'hydrus server shut down at ' + time.ctime() )
|
||||
|
||||
|
||||
|
||||
sys.stdout = initial_sys_stdout
|
||||
sys.stderr = initial_sys_stderr
|
||||
|
||||
except:
|
||||
|
||||
import traceback
|
||||
|
||||
print( 'Critical error occured! Details written to crash.log!' )
|
||||
|
||||
with open( 'crash.log', 'wb' ) as f: f.write( traceback.format_exc() )
|
||||
|
76
test.py
76
test.py
|
@ -38,11 +38,13 @@ from include import ClientCaches
|
|||
from include import ClientData
|
||||
from include import HydrusData
|
||||
|
||||
HydrusGlobals.instance = HC.HYDRUS_TEST
|
||||
|
||||
only_run = None
|
||||
|
||||
class App( wx.App ):
|
||||
class Controller( object ):
|
||||
|
||||
def OnInit( self ):
|
||||
def __init__( self ):
|
||||
|
||||
HydrusGlobals.controller = self
|
||||
self._pubsub = HydrusPubSub.HydrusPubSub( self )
|
||||
|
@ -94,32 +96,6 @@ class App( wx.App ):
|
|||
|
||||
self._cookies = {}
|
||||
|
||||
suites = []
|
||||
|
||||
if only_run is None: run_all = True
|
||||
else: run_all = False
|
||||
|
||||
if run_all or only_run == 'cc': suites.append( unittest.TestLoader().loadTestsFromModule( TestClientConstants ) )
|
||||
if run_all or only_run == 'daemons': suites.append( unittest.TestLoader().loadTestsFromModule( TestClientDaemons ) )
|
||||
if run_all or only_run == 'dialogs': suites.append( unittest.TestLoader().loadTestsFromModule( TestDialogs ) )
|
||||
if run_all or only_run == 'db': suites.append( unittest.TestLoader().loadTestsFromModule( TestDB ) )
|
||||
if run_all or only_run == 'downloading': suites.append( unittest.TestLoader().loadTestsFromModule( TestClientDownloading ) )
|
||||
if run_all or only_run == 'encryption': suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusEncryption ) )
|
||||
if run_all or only_run == 'functions': suites.append( unittest.TestLoader().loadTestsFromModule( TestFunctions ) )
|
||||
if run_all or only_run == 'image': suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusImageHandling ) )
|
||||
if run_all or only_run == 'nat': suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusNATPunch ) )
|
||||
if run_all or only_run == 'server': suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusServer ) )
|
||||
if run_all or only_run == 'sessions': suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusSessions ) )
|
||||
if run_all or only_run == 'tags': suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusTags ) )
|
||||
|
||||
suite = unittest.TestSuite( suites )
|
||||
|
||||
runner = unittest.TextTestRunner( verbosity = 1 )
|
||||
|
||||
runner.run( suite )
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def pub( self, topic, *args, **kwargs ):
|
||||
|
||||
|
@ -174,6 +150,33 @@ class App( wx.App ):
|
|||
|
||||
def ResetIdleTimer( self ): pass
|
||||
|
||||
def Run( self ):
|
||||
|
||||
suites = []
|
||||
|
||||
if only_run is None: run_all = True
|
||||
else: run_all = False
|
||||
|
||||
if run_all or only_run == 'cc': suites.append( unittest.TestLoader().loadTestsFromModule( TestClientConstants ) )
|
||||
if run_all or only_run == 'daemons': suites.append( unittest.TestLoader().loadTestsFromModule( TestClientDaemons ) )
|
||||
if run_all or only_run == 'dialogs': suites.append( unittest.TestLoader().loadTestsFromModule( TestDialogs ) )
|
||||
if run_all or only_run == 'db': suites.append( unittest.TestLoader().loadTestsFromModule( TestDB ) )
|
||||
if run_all or only_run == 'downloading': suites.append( unittest.TestLoader().loadTestsFromModule( TestClientDownloading ) )
|
||||
if run_all or only_run == 'encryption': suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusEncryption ) )
|
||||
if run_all or only_run == 'functions': suites.append( unittest.TestLoader().loadTestsFromModule( TestFunctions ) )
|
||||
if run_all or only_run == 'image': suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusImageHandling ) )
|
||||
if run_all or only_run == 'nat': suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusNATPunch ) )
|
||||
if run_all or only_run == 'server': suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusServer ) )
|
||||
if run_all or only_run == 'sessions': suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusSessions ) )
|
||||
if run_all or only_run == 'tags': suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusTags ) )
|
||||
|
||||
suite = unittest.TestSuite( suites )
|
||||
|
||||
runner = unittest.TextTestRunner( verbosity = 1 )
|
||||
|
||||
runner.run( suite )
|
||||
|
||||
|
||||
def SetHTTP( self, http ): self._http = http
|
||||
|
||||
def SetRead( self, name, value ): self._reads[ name ] = value
|
||||
|
@ -213,17 +216,28 @@ if __name__ == '__main__':
|
|||
|
||||
threading.Thread( target = reactor.run, kwargs = { 'installSignalHandlers' : 0 } ).start()
|
||||
|
||||
app = App()
|
||||
controller = Controller()
|
||||
|
||||
app = wx.App()
|
||||
|
||||
win = wx.Frame( None )
|
||||
|
||||
wx.CallAfter( controller.Run )
|
||||
#threading.Thread( target = controller.Run ).start()
|
||||
|
||||
wx.CallAfter( win.Destroy )
|
||||
|
||||
app.MainLoop()
|
||||
|
||||
finally:
|
||||
|
||||
HydrusGlobals.view_shutdown = True
|
||||
|
||||
app.pubimmediate( 'wake_daemons' )
|
||||
controller.pubimmediate( 'wake_daemons' )
|
||||
|
||||
HydrusGlobals.model_shutdown = True
|
||||
|
||||
app.pubimmediate( 'shutdown' )
|
||||
controller.pubimmediate( 'wake_daemons' )
|
||||
|
||||
reactor.callFromThread( reactor.stop )
|
||||
|
||||
|
|
Loading…
Reference in New Issue