#!/usr/bin/env python3 # Hydrus is released under WTFPL # You just DO WHAT THE FUCK YOU WANT TO. # https://github.com/sirkris/WTFPL/blob/master/WTFPL.md import locale try: locale.setlocale( locale.LC_ALL, '' ) except: pass import sys try: import os import argparse from hydrus.core import HydrusBoot HydrusBoot.AddBaseDirToEnvPath() # initialise Qt here, important it is done early from hydrus.client.gui import QtInit from hydrus.core import HydrusConstants as HC HC.RUNNING_CLIENT = True from hydrus.core import HydrusData from hydrus.core import HydrusGlobals as HG from hydrus.core import HydrusLogger from hydrus.core import HydrusPaths from hydrus.core import HydrusTemp from hydrus.core import HydrusTime argparser = argparse.ArgumentParser( description = 'hydrus network client' ) argparser.add_argument( '-d', '--db_dir', help = 'set an external db location' ) argparser.add_argument( '--temp_dir', help = 'override the program\'s temporary directory' ) argparser.add_argument( '--db_journal_mode', default = 'WAL', choices = [ 'WAL', 'TRUNCATE', 'PERSIST', 'MEMORY' ], help = 'change db journal mode (default=WAL)' ) argparser.add_argument( '--db_cache_size', type = int, help = 'override SQLite cache_size per db file, in MB (default=256)' ) argparser.add_argument( '--db_transaction_commit_period', type = int, help = 'override how often (in seconds) database changes are saved to disk (default=30,min=10)' ) argparser.add_argument( '--db_synchronous_override', type = int, choices = range(4), help = 'override SQLite Synchronous PRAGMA (default=2)' ) argparser.add_argument( '--no_db_temp_files', action='store_true', help = 'run db temp operations entirely in memory' ) argparser.add_argument( '--boot_debug', action='store_true', help = 'print additional bootup information to the log' ) argparser.add_argument( '--profile_mode', action='store_true', help = 'start the program with profile mode on, capturing boot performance' ) argparser.add_argument( '--win_qt_darkmode_test', action='store_true', help = 'Try Qt\'s automatic darkmode recognition.' ) argparser.add_argument( '--no_wal', action='store_true', help = 'OBSOLETE: run using TRUNCATE db journaling' ) argparser.add_argument( '--db_memory_journaling', action='store_true', help = 'OBSOLETE: run using MEMORY db journaling (DANGEROUS)' ) result = argparser.parse_args() db_dir = HydrusPaths.FigureOutDBDir( result.db_dir ) HG.db_journal_mode = result.db_journal_mode if result.no_wal: HG.db_journal_mode = 'TRUNCATE' if result.db_memory_journaling: HG.db_journal_mode = 'MEMORY' if result.db_cache_size is not None: HG.db_cache_size = result.db_cache_size else: HG.db_cache_size = 256 if result.db_transaction_commit_period is not None: HG.db_transaction_commit_period = max( 10, result.db_transaction_commit_period ) else: HG.db_transaction_commit_period = 30 if result.db_synchronous_override is not None: HG.db_synchronous = int( result.db_synchronous_override ) else: if HG.db_journal_mode == 'WAL': HG.db_synchronous = 1 else: HG.db_synchronous = 2 HG.no_db_temp_files = result.no_db_temp_files HG.boot_debug = result.boot_debug HG.profile_mode = result.profile_mode HG.profile_start_time = HydrusTime.GetNow() if HC.PLATFORM_WINDOWS and result.win_qt_darkmode_test: QtInit.DoWinDarkMode() try: from twisted.internet import reactor except Exception as e: import traceback HG.twisted_is_broke_exception = traceback.format_exc() HG.twisted_is_broke = True if result.temp_dir is not None: HydrusTemp.SetEnvTempDir( result.temp_dir ) except Exception as e: title = 'Critical boot error occurred! Details written to crash.log in either your db dir, userdir, or desktop!' try: HydrusData.DebugPrint( title ) HydrusData.PrintException( e ) except: pass import traceback error_trace = str( e ) + '\n\n' + traceback.format_exc() if 'db_dir' in locals() and os.path.exists( db_dir ): emergency_dir = db_dir else: emergency_dir = os.path.expanduser( '~' ) possible_desktop = os.path.join( emergency_dir, 'Desktop' ) if os.path.exists( possible_desktop ) and os.path.isdir( possible_desktop ): emergency_dir = possible_desktop dest_path = os.path.join( emergency_dir, 'hydrus_crash.log' ) with open( dest_path, 'w', encoding = 'utf-8' ) as f: f.write( title ) f.write( '\n\n' ) f.write( error_trace ) try: from qtpy import QtWidgets app = QtWidgets.QApplication( sys.argv ) from hydrus.client.gui import ClientGUIDialogsMessage ClientGUIDialogsMessage.ShowCritical( None, title, error_trace ) except: HydrusData.DebugPrint( 'Could not start up Qt to show the error visually!' ) sys.exit( 1 ) def boot(): controller = None with HydrusLogger.HydrusLogger( db_dir, 'client' ) as logger: try: HydrusData.Print( 'hydrus client started' ) if not HG.twisted_is_broke: import threading threading.Thread( target = reactor.run, name = 'twisted', kwargs = { 'installSignalHandlers' : 0 } ).start() from hydrus.client import ClientController controller = ClientController.Controller( db_dir ) controller.Run() except: HydrusData.Print( 'hydrus client failed' ) import traceback HydrusData.Print( traceback.format_exc() ) finally: HG.started_shutdown = True HG.view_shutdown = True HG.model_shutdown = True if controller is not None: controller.pubimmediate( 'wake_daemons' ) if not HG.twisted_is_broke: reactor.callFromThread( reactor.stop ) HydrusData.Print( 'hydrus client shut down' ) HG.shutdown_complete = True if HG.restart: HydrusData.RestartProcess()