Version 231
This commit is contained in:
parent
fc7605c13a
commit
ab1bd6d208
|
@ -66,9 +66,7 @@ try:
|
|||
|
||||
#
|
||||
|
||||
log_path = os.path.join( db_dir, 'client.log' )
|
||||
|
||||
with HydrusLogger.HydrusLogger( log_path ) as logger:
|
||||
with HydrusLogger.HydrusLogger( db_dir, 'client' ) as logger:
|
||||
|
||||
try:
|
||||
|
||||
|
|
|
@ -66,9 +66,7 @@ try:
|
|||
|
||||
#
|
||||
|
||||
log_path = os.path.join( db_dir, 'client.log' )
|
||||
|
||||
with HydrusLogger.HydrusLogger( log_path ) as logger:
|
||||
with HydrusLogger.HydrusLogger( db_dir, 'client' ) as logger:
|
||||
|
||||
try:
|
||||
|
||||
|
|
|
@ -8,6 +8,26 @@
|
|||
<div class="content">
|
||||
<h3>changelog</h3>
|
||||
<ul>
|
||||
<li><h3>version 231</h3></li>
|
||||
<ul>
|
||||
<li>added file lookup scripts suggested tags control and appropriate options panel</li>
|
||||
<li>added final bit of gui->filelookup script->content update pipeline conversion and tie-in code</li>
|
||||
<li>moved all the suggested tag options into a notebook</li>
|
||||
<li>added notebook layout for suggested tag control columns. it is now the default</li>
|
||||
<li>suggested tag columns now have a unified set width</li>
|
||||
<li>the parsing ui's add script and node buttons now spawn menus rather than the awkward listofstrings dialog</li>
|
||||
<li>added 'iqdb danbooru' file lookup script. it hangs the ui pretty bad atm, but that will change in future</li>
|
||||
<li>fixed a critical pyinstaller problem with the os x builds</li>
|
||||
<li>log files will now be appending with 'year-month', and will roll over to a new file as the month turns</li>
|
||||
<li>help->about dialog now has some library version information</li>
|
||||
<li>converted more menu stuff to the new system</li>
|
||||
<li>wrote the guts of a new png-based object sharing system</li>
|
||||
<li>dropdown choices are more resistant to missing init and invalid defaults</li>
|
||||
<li>tweaked some disk cache maintenance timing</li>
|
||||
<li>fixed a multi-version update bug regarding external thumbnail paths not being initalised</li>
|
||||
<li>misc cleanup</li>
|
||||
<li>misc cleanup, improvements</li>
|
||||
</ul>
|
||||
<li><h3>version 230</h3></li>
|
||||
<ul>
|
||||
<li>all multiline text ctrls now support ctrl+a for select all, wew</li>
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import collections
|
||||
import cv2
|
||||
import HydrusConstants as HC
|
||||
import HydrusExceptions
|
||||
import os
|
||||
import PIL
|
||||
import ssl
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
|
@ -40,7 +43,22 @@ Shift-LeftClick-Drag - Drag (in Filter)
|
|||
Ctrl + MouseWheel - Zoom
|
||||
Z - Zoom Full/Fit'''
|
||||
|
||||
CLIENT_DESCRIPTION = '''This client is the media management application of the hydrus software suite.'''
|
||||
library_versions = []
|
||||
|
||||
library_versions.append( ( 'openssl', ssl.OPENSSL_VERSION ) )
|
||||
library_versions.append( ( 'PIL', PIL.VERSION ) )
|
||||
|
||||
if hasattr( PIL, 'PILLOW_VERSION' ):
|
||||
|
||||
library_versions.append( ( 'Pillow', PIL.PILLOW_VERSION ) )
|
||||
|
||||
|
||||
library_versions.append( ( 'OpenCV', cv2.__version__ ) )
|
||||
library_versions.append( ( 'wx', wx.version() ) )
|
||||
|
||||
CLIENT_DESCRIPTION = 'This client is the media management application of the hydrus software suite.'
|
||||
|
||||
CLIENT_DESCRIPTION += os.linesep * 2 + os.linesep.join( ( lib + ': ' + version for ( lib, version ) in library_versions ) )
|
||||
|
||||
COLLECT_BY_S = 0
|
||||
COLLECT_BY_SV = 1
|
||||
|
|
|
@ -650,7 +650,7 @@ class Controller( HydrusController.HydrusController ):
|
|||
|
||||
if not self.CurrentlyVeryIdle():
|
||||
|
||||
stop_time = HydrusData.GetNow() + 30
|
||||
stop_time = HydrusData.GetNow() + 10
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -5362,6 +5362,11 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
def _LoadIntoDiskCache( self, stop_time = None, caller_limit = None ):
|
||||
|
||||
if stop_time is None:
|
||||
|
||||
stop_time = HydrusData.GetNow() + 5
|
||||
|
||||
|
||||
self._CloseDBCursor()
|
||||
|
||||
try:
|
||||
|
@ -7874,7 +7879,12 @@ class DB( HydrusDB.HydrusDB ):
|
|||
|
||||
if version == 229:
|
||||
|
||||
self._c.executemany( 'INSERT INTO json_dumps_named VALUES ( ?, ?, ?, ? );', [ ( 32, 'gelbooru md5', 1, '''["http://gelbooru.com/index.php", 0, 1, 1, "md5", {"s": "list", "page": "post"}, [[30, 1, ["we got sent back to main gallery page -- title test", 8, [27, 1, [[["head", {}, 0], ["title", {}, 0]], null]], [true, true, "Image List"]]], [30, 1, ["", 0, [27, 1, [[["li", {"class": "tag-type-general"}, null], ["a", {}, 1]], null]], ""]], [30, 1, ["", 0, [27, 1, [[["li", {"class": "tag-type-copyright"}, null], ["a", {}, 1]], null]], "series"]], [30, 1, ["", 0, [27, 1, [[["li", {"class": "tag-type-artist"}, null], ["a", {}, 1]], null]], "creator"]], [30, 1, ["", 0, [27, 1, [[["li", {"class": "tag-type-character"}, null], ["a", {}, 1]], null]], "character"]], [30, 1, ["we got sent back to main gallery page -- page links exist", 8, [27, 1, [[["div", {}, null]], "class"]], [true, true, "pagination"]]]]]''' ) ] )
|
||||
self._c.executemany( 'INSERT OR IGNORE INTO json_dumps_named VALUES ( ?, ?, ?, ? );', [ ( 32, 'gelbooru md5', 1, '''["http://gelbooru.com/index.php", 0, 1, 1, "md5", {"s": "list", "page": "post"}, [[30, 1, ["we got sent back to main gallery page -- title test", 8, [27, 1, [[["head", {}, 0], ["title", {}, 0]], null]], [true, true, "Image List"]]], [30, 1, ["", 0, [27, 1, [[["li", {"class": "tag-type-general"}, null], ["a", {}, 1]], null]], ""]], [30, 1, ["", 0, [27, 1, [[["li", {"class": "tag-type-copyright"}, null], ["a", {}, 1]], null]], "series"]], [30, 1, ["", 0, [27, 1, [[["li", {"class": "tag-type-artist"}, null], ["a", {}, 1]], null]], "creator"]], [30, 1, ["", 0, [27, 1, [[["li", {"class": "tag-type-character"}, null], ["a", {}, 1]], null]], "character"]], [30, 1, ["we got sent back to main gallery page -- page links exist", 8, [27, 1, [[["div", {}, null]], "class"]], [true, true, "pagination"]]]]]''' ) ] )
|
||||
|
||||
|
||||
if version == 230:
|
||||
|
||||
self._c.executemany( 'INSERT OR IGNORE INTO json_dumps_named VALUES ( ?, ?, ?, ? );', [ ( 32, 'iqdb danbooru', 1, '''["http://danbooru.iqdb.org/", 1, 0, 0, "file", {}, [[29, 1, ["link to danbooru", [27, 1, [[["td", {"class": "image"}, 1], ["a", {}, 0]], "href"]], [[30, 1, ["", 0, [27, 1, [[["section", {"id": "tag-list"}, 0], ["li", {"class": "category-1"}, null], ["a", {"class": "search-tag"}, 0]], null]], "creator"]], [30, 1, ["", 0, [27, 1, [[["section", {"id": "tag-list"}, 0], ["li", {"class": "category-3"}, null], ["a", {"class": "search-tag"}, 0]], null]], "series"]], [30, 1, ["", 0, [27, 1, [[["section", {"id": "tag-list"}, 0], ["li", {"class": "category-4"}, null], ["a", {"class": "search-tag"}, 0]], null]], "character"]], [30, 1, ["", 0, [27, 1, [[["section", {"id": "tag-list"}, 0], ["li", {"class": "category-0"}, null], ["a", {"class": "search-tag"}, 0]], null]], ""]]]]], [30, 1, ["no iqdb match found", 8, [27, 1, [[["th", {}, null]], null]], [false, true, "Best match"]]]]]''' ) ] )
|
||||
|
||||
|
||||
self._controller.pub( 'splash_set_title_text', 'updated db to v' + str( version + 1 ) )
|
||||
|
|
|
@ -5,7 +5,6 @@ import ClientFiles
|
|||
import ClientNetworking
|
||||
import ClientThreading
|
||||
import collections
|
||||
import datetime
|
||||
import HydrusConstants as HC
|
||||
import HydrusExceptions
|
||||
import HydrusFileHandling
|
||||
|
@ -536,6 +535,7 @@ class ClientOptions( HydrusSerialisable.SerialisableBase ):
|
|||
self._dictionary[ 'booleans' ][ 'replace_siblings_on_manage_tags' ] = True
|
||||
|
||||
self._dictionary[ 'booleans' ][ 'show_related_tags' ] = False
|
||||
self._dictionary[ 'booleans' ][ 'show_file_lookup_script_tags' ] = False
|
||||
self._dictionary[ 'booleans' ][ 'hide_message_manager_on_gui_iconise' ] = HC.PLATFORM_OSX
|
||||
self._dictionary[ 'booleans' ][ 'hide_message_manager_on_gui_deactive' ] = False
|
||||
|
||||
|
@ -547,11 +547,12 @@ class ClientOptions( HydrusSerialisable.SerialisableBase ):
|
|||
|
||||
self._dictionary[ 'integers' ][ 'video_buffer_size_mb' ] = 96
|
||||
|
||||
self._dictionary[ 'integers' ][ 'related_tags_width' ] = 150
|
||||
self._dictionary[ 'integers' ][ 'related_tags_search_1_duration_ms' ] = 250
|
||||
self._dictionary[ 'integers' ][ 'related_tags_search_2_duration_ms' ] = 2000
|
||||
self._dictionary[ 'integers' ][ 'related_tags_search_3_duration_ms' ] = 6000
|
||||
|
||||
self._dictionary[ 'integers' ][ 'suggested_tags_width' ] = 300
|
||||
|
||||
#
|
||||
|
||||
self._dictionary[ 'keys' ] = {}
|
||||
|
@ -567,14 +568,19 @@ class ClientOptions( HydrusSerialisable.SerialisableBase ):
|
|||
self._dictionary[ 'noneable_integers' ][ 'disk_cache_maintenance_mb' ] = 256
|
||||
self._dictionary[ 'noneable_integers' ][ 'disk_cache_init_period' ] = 4
|
||||
|
||||
self._dictionary[ 'noneable_integers' ][ 'suggested_tags_width' ] = None
|
||||
|
||||
self._dictionary[ 'noneable_integers' ][ 'num_recent_tags' ] = None
|
||||
|
||||
self._dictionary[ 'noneable_integers' ][ 'maintenance_vacuum_period_days' ] = 30
|
||||
|
||||
#
|
||||
|
||||
self._dictionary[ 'noneable_strings' ] = {}
|
||||
|
||||
self._dictionary[ 'noneable_strings' ][ 'favourite_file_lookup_script' ] = 'gelbooru md5'
|
||||
self._dictionary[ 'noneable_strings' ][ 'suggested_tags_layout' ] = 'notebook'
|
||||
|
||||
#
|
||||
|
||||
client_files_default = os.path.join( db_dir, 'client_files' )
|
||||
|
||||
self._dictionary[ 'client_files_locations_ideal_weights' ] = [ ( HydrusPaths.ConvertAbsPathToPortablePath( client_files_default ), 1.0 ) ]
|
||||
|
@ -752,20 +758,29 @@ class ClientOptions( HydrusSerialisable.SerialisableBase ):
|
|||
|
||||
loaded_dictionary = HydrusSerialisable.CreateFromSerialisableTuple( old_serialisable_info )
|
||||
|
||||
updated_cfliw = []
|
||||
|
||||
for ( old_portable_path, weight ) in loaded_dictionary[ 'client_files_locations_ideal_weights' ]:
|
||||
if 'client_files_locations_ideal_weights' in loaded_dictionary:
|
||||
|
||||
new_portable_path = update_portable_path( old_portable_path )
|
||||
updated_cfliw = []
|
||||
|
||||
updated_cfliw.append( ( new_portable_path, weight ) )
|
||||
for ( old_portable_path, weight ) in loaded_dictionary[ 'client_files_locations_ideal_weights' ]:
|
||||
|
||||
new_portable_path = update_portable_path( old_portable_path )
|
||||
|
||||
updated_cfliw.append( ( new_portable_path, weight ) )
|
||||
|
||||
|
||||
loaded_dictionary[ 'client_files_locations_ideal_weights' ] = updated_cfliw
|
||||
|
||||
|
||||
loaded_dictionary[ 'client_files_locations_ideal_weights' ] = updated_cfliw
|
||||
if 'client_files_locations_resized_thumbnail_override' in loaded_dictionary:
|
||||
|
||||
loaded_dictionary[ 'client_files_locations_resized_thumbnail_override' ] = update_portable_path( loaded_dictionary[ 'client_files_locations_resized_thumbnail_override' ] )
|
||||
|
||||
|
||||
loaded_dictionary[ 'client_files_locations_resized_thumbnail_override' ] = update_portable_path( loaded_dictionary[ 'client_files_locations_resized_thumbnail_override' ] )
|
||||
|
||||
loaded_dictionary[ 'client_files_locations_full_size_thumbnail_override' ] = update_portable_path( loaded_dictionary[ 'client_files_locations_full_size_thumbnail_override' ] )
|
||||
if 'client_files_locations_full_size_thumbnail_override' in loaded_dictionary:
|
||||
|
||||
loaded_dictionary[ 'client_files_locations_full_size_thumbnail_override' ] = update_portable_path( loaded_dictionary[ 'client_files_locations_full_size_thumbnail_override' ] )
|
||||
|
||||
|
||||
new_serialisable_info = loaded_dictionary.GetSerialisableTuple()
|
||||
|
||||
|
@ -983,6 +998,14 @@ class ClientOptions( HydrusSerialisable.SerialisableBase ):
|
|||
|
||||
|
||||
|
||||
def GetNoneableString( self, name ):
|
||||
|
||||
with self._lock:
|
||||
|
||||
return self._dictionary[ 'noneable_strings' ][ name ]
|
||||
|
||||
|
||||
|
||||
def GetPreviewShowAction( self, mime ):
|
||||
|
||||
with self._lock:
|
||||
|
@ -1094,6 +1117,14 @@ class ClientOptions( HydrusSerialisable.SerialisableBase ):
|
|||
|
||||
|
||||
|
||||
def SetNoneableString( self, name, value ):
|
||||
|
||||
with self._lock:
|
||||
|
||||
self._dictionary[ 'noneable_strings' ][ name ] = value
|
||||
|
||||
|
||||
|
||||
def SetSuggestedTagsFavourites( self, service_key, tags ):
|
||||
|
||||
with self._lock:
|
||||
|
|
|
@ -567,6 +567,7 @@ def GetDefaultScriptRows():
|
|||
script_info = []
|
||||
|
||||
script_info.append( ( 32, 'gelbooru md5', 1, '''["http://gelbooru.com/index.php", 0, 1, 1, "md5", {"s": "list", "page": "post"}, [[30, 1, ["we got sent back to main gallery page -- title test", 8, [27, 1, [[["head", {}, 0], ["title", {}, 0]], null]], [true, true, "Image List"]]], [30, 1, ["", 0, [27, 1, [[["li", {"class": "tag-type-general"}, null], ["a", {}, 1]], null]], ""]], [30, 1, ["", 0, [27, 1, [[["li", {"class": "tag-type-copyright"}, null], ["a", {}, 1]], null]], "series"]], [30, 1, ["", 0, [27, 1, [[["li", {"class": "tag-type-artist"}, null], ["a", {}, 1]], null]], "creator"]], [30, 1, ["", 0, [27, 1, [[["li", {"class": "tag-type-character"}, null], ["a", {}, 1]], null]], "character"]], [30, 1, ["we got sent back to main gallery page -- page links exist", 8, [27, 1, [[["div", {}, null]], "class"]], [true, true, "pagination"]]]]]''' ) )
|
||||
script_info.append( ( 32, 'iqdb danbooru', 1, '''["http://danbooru.iqdb.org/", 1, 0, 0, "file", {}, [[29, 1, ["link to danbooru", [27, 1, [[["td", {"class": "image"}, 1], ["a", {}, 0]], "href"]], [[30, 1, ["", 0, [27, 1, [[["section", {"id": "tag-list"}, 0], ["li", {"class": "category-1"}, null], ["a", {"class": "search-tag"}, 0]], null]], "creator"]], [30, 1, ["", 0, [27, 1, [[["section", {"id": "tag-list"}, 0], ["li", {"class": "category-3"}, null], ["a", {"class": "search-tag"}, 0]], null]], "series"]], [30, 1, ["", 0, [27, 1, [[["section", {"id": "tag-list"}, 0], ["li", {"class": "category-4"}, null], ["a", {"class": "search-tag"}, 0]], null]], "character"]], [30, 1, ["", 0, [27, 1, [[["section", {"id": "tag-list"}, 0], ["li", {"class": "category-0"}, null], ["a", {"class": "search-tag"}, 0]], null]], ""]]]]], [30, 1, ["no iqdb match found", 8, [27, 1, [[["th", {}, null]], null]], [false, true, "Best match"]]]]]''' ) )
|
||||
|
||||
return script_info
|
||||
|
|
@ -721,26 +721,29 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
|
|||
|
||||
def file():
|
||||
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'import_files' ), p( '&Import Files' ), p( 'Add new files to the database.' ) )
|
||||
ClientGUIMenus.AppendMenuItem( menu, 'import files', 'Add new files to the database.', self, self._ImportFiles )
|
||||
menu.AppendSeparator()
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'manage_import_folders' ), p( 'Manage Import Folders' ), p( 'Manage folders from which the client can automatically import.' ) )
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'manage_export_folders' ), p( 'Manage Export Folders' ), p( 'Manage folders to which the client can automatically export.' ) )
|
||||
ClientGUIMenus.AppendMenuItem( menu, 'manage import folders', 'Manage folders from which the client can automatically import.', self, self._ManageImportFolders )
|
||||
ClientGUIMenus.AppendMenuItem( menu, 'manage export folders', 'Manage folders to which the client can automatically export.', self, self._ManageExportFolders )
|
||||
|
||||
menu.AppendSeparator()
|
||||
|
||||
open = wx.Menu()
|
||||
|
||||
open.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'open_install_folder' ), p( 'Installation Directory' ), p( 'Open the installation directory for this client.' ) )
|
||||
open.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'open_db_folder' ), p( 'Database Directory' ), p( 'Open the database directory for this instance of the client.' ) )
|
||||
open.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'open_export_folder' ), p( 'Quick Export Directory' ), p( 'Open the export directory so you can easily access the files you have exported.' ) )
|
||||
ClientGUIMenus.AppendMenuItem( open, 'installation directory', 'Open the installation directory for this client.', self, self._OpenInstallFolder )
|
||||
ClientGUIMenus.AppendMenuItem( open, 'database directory', 'Open the database directory for this instance of the client.', self, self._OpenDBFolder )
|
||||
ClientGUIMenus.AppendMenuItem( open, 'quick export directory', 'Open the export directory so you can easily access the files you have exported.', self, self._OpenExportFolder )
|
||||
|
||||
menu.AppendMenu( CC.ID_NULL, p( 'Open' ), open )
|
||||
ClientGUIMenus.AppendMenu( menu, open, 'open' )
|
||||
|
||||
menu.AppendSeparator()
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'options' ), p( '&Options' ) )
|
||||
|
||||
ClientGUIMenus.AppendMenuItem( menu, 'options', 'Change how the client operates.', self, self._ManageOptions )
|
||||
|
||||
menu.AppendSeparator()
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'restart' ), p( '&Restart' ) )
|
||||
menu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'exit' ), p( '&Exit' ) )
|
||||
|
||||
ClientGUIMenus.AppendMenuItem( menu, 'restart', 'Shut the client down and then start it up again.', self, self.Exit, restart = True )
|
||||
ClientGUIMenus.AppendMenuItem( menu, 'exit', 'Shut the client down.', self, self.Exit )
|
||||
|
||||
return ( menu, p( '&File' ), True )
|
||||
|
||||
|
@ -1188,8 +1191,6 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
|
|||
pubsub_profile_mode_id = ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'pubsub_profile_mode' )
|
||||
force_idle_mode_id = ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'force_idle_mode' )
|
||||
|
||||
no_focus_changed_id = ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'no_focus_changed' )
|
||||
|
||||
debug = wx.Menu()
|
||||
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'debug_make_popups' ), p( 'Make Some Popups' ) )
|
||||
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'debug_make_a_delayed_popup' ), p( 'Make a Popup in Five Seconds' ) )
|
||||
|
@ -1199,8 +1200,6 @@ class FrameGUI( ClientGUITopLevelWindows.FrameThatResizes ):
|
|||
debug.Check( pubsub_profile_mode_id, HydrusGlobals.pubsub_profile_mode )
|
||||
debug.AppendCheckItem( force_idle_mode_id, p( '&Force Idle Mode' ) )
|
||||
debug.Check( force_idle_mode_id, HydrusGlobals.force_idle_mode )
|
||||
debug.AppendCheckItem( no_focus_changed_id, p( '&No Focus Changed Mode' ) )
|
||||
debug.Check( no_focus_changed_id, HydrusGlobals.no_focus_changed )
|
||||
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'debug_garbage' ), p( 'Garbage' ) )
|
||||
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'clear_caches' ), p( '&Clear Preview/Fullscreen Caches' ) )
|
||||
debug.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetPermanentId( 'delete_service_info' ), p( '&Clear DB Service Info Cache' ), p( 'Delete all cached service info, in case it has become desynchronised.' ) )
|
||||
|
@ -2439,10 +2438,6 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
self._controller.pub( 'notify_new_sessions' )
|
||||
|
||||
elif command == 'delete_service_info': self._DeleteServiceInfo()
|
||||
elif command == 'exit':
|
||||
|
||||
self.Exit()
|
||||
|
||||
elif command == 'fetch_ip': self._FetchIP( data )
|
||||
elif command == 'force_idle_mode':
|
||||
|
||||
|
@ -2452,7 +2447,6 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
elif command == 'help': webbrowser.open( 'file://' + HC.HELP_DIR + '/index.html' )
|
||||
elif command == 'help_about': self._AboutWindow()
|
||||
elif command == 'help_shortcuts': wx.MessageBox( CC.SHORTCUT_HELP )
|
||||
elif command == 'import_files': self._ImportFiles()
|
||||
elif command == 'load_gui_session': self._LoadGUISession( data )
|
||||
elif command == 'load_into_disk_cache':
|
||||
|
||||
|
@ -2460,8 +2454,6 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
|
||||
elif command == 'manage_account_types': self._ManageAccountTypes( data )
|
||||
elif command == 'manage_boorus': self._ManageBoorus()
|
||||
elif command == 'manage_export_folders': self._ManageExportFolders()
|
||||
elif command == 'manage_import_folders': self._ManageImportFolders()
|
||||
elif command == 'manage_parsing_scripts': self._ManageParsingScripts()
|
||||
elif command == 'manage_pixiv_account': self._ManagePixivAccount()
|
||||
elif command == 'manage_server_services': self._ManageServer( data )
|
||||
|
@ -2491,14 +2483,6 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
|
||||
elif command == 'new_page_query': self._NewPageQuery( data )
|
||||
elif command == 'news': self._News( data )
|
||||
elif command == 'no_focus_changed':
|
||||
|
||||
HydrusGlobals.no_focus_changed = not HydrusGlobals.no_focus_changed
|
||||
|
||||
elif command == 'open_db_folder': self._OpenDBFolder()
|
||||
elif command == 'open_export_folder': self._OpenExportFolder()
|
||||
elif command == 'open_install_folder': self._OpenInstallFolder()
|
||||
elif command == 'options': self._ManageOptions()
|
||||
elif command == 'patreon': webbrowser.open( 'https://www.patreon.com/hydrus_dev' )
|
||||
elif command == 'pause_export_folders_sync': self._PauseSync( 'export_folders' )
|
||||
elif command == 'pause_import_folders_sync': self._PauseSync( 'import_folders' )
|
||||
|
@ -2517,10 +2501,6 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
|
|||
|
||||
if page is not None: page.RefreshQuery()
|
||||
|
||||
elif command == 'restart':
|
||||
|
||||
self.Exit( restart = True )
|
||||
|
||||
elif command == 'review_services': self._ReviewServices()
|
||||
elif command == 'save_gui_session': self._SaveGUISession()
|
||||
elif command == 'set_media_focus': self._SetMediaFocus()
|
||||
|
|
|
@ -1976,11 +1976,6 @@ class CanvasPanel( Canvas ):
|
|||
|
||||
def FocusChanged( self, page_key, media ):
|
||||
|
||||
if HydrusGlobals.no_focus_changed:
|
||||
|
||||
return
|
||||
|
||||
|
||||
if HC.options[ 'hide_preview' ]:
|
||||
|
||||
return
|
||||
|
|
|
@ -207,7 +207,8 @@ class BetterChoice( wx.Choice ):
|
|||
selection = self.GetSelection()
|
||||
|
||||
if selection != wx.NOT_FOUND: return self.GetClientData( selection )
|
||||
else: return self.GetClientData( 0 )
|
||||
elif self.GetCount() > 0: return self.GetClientData( 0 )
|
||||
else: return None
|
||||
|
||||
|
||||
def SelectClientData( self, client_data ):
|
||||
|
@ -222,7 +223,10 @@ class BetterChoice( wx.Choice ):
|
|||
|
||||
|
||||
|
||||
self.Select( 0 )
|
||||
if self.GetCount() > 0:
|
||||
|
||||
self.Select( 0 )
|
||||
|
||||
|
||||
|
||||
class BufferedWindow( wx.Window ):
|
||||
|
|
|
@ -1818,6 +1818,8 @@ class DialogInputLocalFiles( Dialog ):
|
|||
|
||||
if size == 0:
|
||||
|
||||
HydrusData.Print( 'Empty file: ' + path )
|
||||
|
||||
num_empty_files += 1
|
||||
|
||||
continue
|
||||
|
@ -1833,6 +1835,8 @@ class DialogInputLocalFiles( Dialog ):
|
|||
|
||||
else:
|
||||
|
||||
HydrusData.Print( 'Unparsable file: ' + path )
|
||||
|
||||
num_uninteresting_mime_files += 1
|
||||
|
||||
continue
|
||||
|
@ -1885,6 +1889,7 @@ class DialogInputLocalFiles( Dialog ):
|
|||
|
||||
message += '.'
|
||||
|
||||
HydrusData.Print( message )
|
||||
|
||||
wx.CallAfter( self.SetGaugeInfo, num_file_paths, num_file_paths, message )
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import ClientConstants as CC
|
||||
import ClientGUICommon
|
||||
import ClientGUIDialogs
|
||||
import ClientGUIMenus
|
||||
import ClientGUIScrolledPanels
|
||||
import ClientGUITopLevelWindows
|
||||
import ClientNetworking
|
||||
|
@ -78,20 +79,15 @@ class EditHTMLFormulaPanel( ClientGUIScrolledPanels.EditPanel ):
|
|||
self._tag_rules = wx.ListBox( edit_panel, style = wx.LB_SINGLE )
|
||||
self._tag_rules.Bind( wx.EVT_LEFT_DCLICK, self.EventEdit )
|
||||
|
||||
self._add_rule = wx.Button( edit_panel, label = 'add' )
|
||||
self._add_rule.Bind( wx.EVT_BUTTON, self.EventAdd )
|
||||
self._add_rule = ClientGUICommon.BetterButton( edit_panel, 'add', self.Add )
|
||||
|
||||
self._edit_rule = wx.Button( edit_panel, label = 'edit' )
|
||||
self._edit_rule.Bind( wx.EVT_BUTTON, self.EventEdit )
|
||||
self._edit_rule = ClientGUICommon.BetterButton( edit_panel, 'edit', self.Edit )
|
||||
|
||||
self._move_rule_up = wx.Button( edit_panel, label = u'\u2191' )
|
||||
self._move_rule_up.Bind( wx.EVT_BUTTON, self.EventMoveUp )
|
||||
self._move_rule_up = ClientGUICommon.BetterButton( edit_panel, u'\u2191', self.MoveUp )
|
||||
|
||||
self._delete_rule = wx.Button( edit_panel, label = 'X' )
|
||||
self._delete_rule.Bind( wx.EVT_BUTTON, self.EventDelete )
|
||||
self._delete_rule = ClientGUICommon.BetterButton( edit_panel, 'X', self.Delete )
|
||||
|
||||
self._move_rule_down = wx.Button( edit_panel, label = u'\u2193' )
|
||||
self._move_rule_down.Bind( wx.EVT_BUTTON, self.EventMoveDown )
|
||||
self._move_rule_down = ClientGUICommon.BetterButton( edit_panel, u'\u2193', self.MoveDown )
|
||||
|
||||
self._content_rule = wx.TextCtrl( edit_panel )
|
||||
|
||||
|
@ -107,8 +103,7 @@ class EditHTMLFormulaPanel( ClientGUIScrolledPanels.EditPanel ):
|
|||
|
||||
self._example_data.SetValue( example_data )
|
||||
|
||||
self._run_test = wx.Button( test_panel, label = 'test parse' )
|
||||
self._run_test.Bind( wx.EVT_BUTTON, self.EventTestParse )
|
||||
self._run_test = ClientGUICommon.BetterButton( test_panel, 'test parse', self.TestParse )
|
||||
|
||||
self._results = ClientGUICommon.SaneMultilineTextCtrl( test_panel )
|
||||
|
||||
|
@ -217,7 +212,7 @@ Leave the 'attribute' blank to fetch the string of the tag (i.e. <p>This part</p
|
|||
self.SetSizer( vbox )
|
||||
|
||||
|
||||
def EventAdd( self, event ):
|
||||
def Add( self ):
|
||||
|
||||
dlg_title = 'edit tag rule'
|
||||
|
||||
|
@ -240,7 +235,7 @@ Leave the 'attribute' blank to fetch the string of the tag (i.e. <p>This part</p
|
|||
|
||||
|
||||
|
||||
def EventDelete( self, event ):
|
||||
def Delete( self ):
|
||||
|
||||
selection = self._tag_rules.GetSelection()
|
||||
|
||||
|
@ -257,7 +252,7 @@ Leave the 'attribute' blank to fetch the string of the tag (i.e. <p>This part</p
|
|||
|
||||
|
||||
|
||||
def EventEdit( self, event ):
|
||||
def Edit( self ):
|
||||
|
||||
selection = self._tag_rules.GetSelection()
|
||||
|
||||
|
@ -286,7 +281,27 @@ Leave the 'attribute' blank to fetch the string of the tag (i.e. <p>This part</p
|
|||
|
||||
|
||||
|
||||
def EventMoveDown( self, event ):
|
||||
def EventEdit( self, event ):
|
||||
|
||||
self.Edit()
|
||||
|
||||
|
||||
def GetValue( self ):
|
||||
|
||||
tags_rules = [ self._tag_rules.GetClientData( i ) for i in range( self._tag_rules.GetCount() ) ]
|
||||
content_rule = self._content_rule.GetValue()
|
||||
|
||||
if content_rule == '':
|
||||
|
||||
content_rule = None
|
||||
|
||||
|
||||
formula = ClientParsing.ParseFormulaHTML( tags_rules, content_rule )
|
||||
|
||||
return formula
|
||||
|
||||
|
||||
def MoveDown( self ):
|
||||
|
||||
selection = self._tag_rules.GetSelection()
|
||||
|
||||
|
@ -301,7 +316,7 @@ Leave the 'attribute' blank to fetch the string of the tag (i.e. <p>This part</p
|
|||
|
||||
|
||||
|
||||
def EventMoveUp( self, event ):
|
||||
def MoveUp( self ):
|
||||
|
||||
selection = self._tag_rules.GetSelection()
|
||||
|
||||
|
@ -316,7 +331,7 @@ Leave the 'attribute' blank to fetch the string of the tag (i.e. <p>This part</p
|
|||
|
||||
|
||||
|
||||
def EventTestParse( self, event ):
|
||||
def TestParse( self ):
|
||||
|
||||
formula = self.GetValue()
|
||||
|
||||
|
@ -342,21 +357,6 @@ Leave the 'attribute' blank to fetch the string of the tag (i.e. <p>This part</p
|
|||
|
||||
|
||||
|
||||
def GetValue( self ):
|
||||
|
||||
tags_rules = [ self._tag_rules.GetClientData( i ) for i in range( self._tag_rules.GetCount() ) ]
|
||||
content_rule = self._content_rule.GetValue()
|
||||
|
||||
if content_rule == '':
|
||||
|
||||
content_rule = None
|
||||
|
||||
|
||||
formula = ClientParsing.ParseFormulaHTML( tags_rules, content_rule )
|
||||
|
||||
return formula
|
||||
|
||||
|
||||
class EditNodes( wx.Panel ):
|
||||
|
||||
def __init__( self, parent, nodes, referral_url_callable, example_data_callable ):
|
||||
|
@ -368,23 +368,17 @@ class EditNodes( wx.Panel ):
|
|||
|
||||
self._nodes = ClientGUICommon.SaneListCtrl( self, 200, [ ( 'name', 120 ), ( 'node type', 80 ), ( 'produces', -1 ) ], delete_key_callback = self.Delete, activation_callback = self.Edit, use_display_tuple_for_sort = True )
|
||||
|
||||
self._add_button = wx.Button( self, label = 'add' )
|
||||
self._add_button.Bind( wx.EVT_BUTTON, self.EventAdd )
|
||||
self._add_button = ClientGUICommon.BetterButton( self, 'add', self.Add )
|
||||
|
||||
self._copy_button = wx.Button( self, label = 'copy' )
|
||||
self._copy_button.Bind( wx.EVT_BUTTON, self.EventCopy )
|
||||
self._copy_button = ClientGUICommon.BetterButton( self, 'copy', self.Copy )
|
||||
|
||||
self._paste_button = wx.Button( self, label = 'paste' )
|
||||
self._paste_button.Bind( wx.EVT_BUTTON, self.EventPaste )
|
||||
self._paste_button = ClientGUICommon.BetterButton( self, 'paste', self.Paste )
|
||||
|
||||
self._duplicate_button = wx.Button( self, label = 'duplicate' )
|
||||
self._duplicate_button.Bind( wx.EVT_BUTTON, self.EventDuplicate )
|
||||
self._duplicate_button = ClientGUICommon.BetterButton( self, 'duplicate', self.Duplicate )
|
||||
|
||||
self._edit_button = wx.Button( self, label = 'edit' )
|
||||
self._edit_button.Bind( wx.EVT_BUTTON, self.EventEdit )
|
||||
self._edit_button = ClientGUICommon.BetterButton( self, 'edit', self.Edit )
|
||||
|
||||
self._delete_button = wx.Button( self, label = 'delete' )
|
||||
self._delete_button.Bind( wx.EVT_BUTTON, self.EventDelete )
|
||||
self._delete_button = ClientGUICommon.BetterButton( self, 'delete', self.Delete )
|
||||
|
||||
#
|
||||
|
||||
|
@ -423,47 +417,54 @@ class EditNodes( wx.Panel ):
|
|||
|
||||
def Add( self ):
|
||||
|
||||
with ClientGUIDialogs.DialogSelectFromListOfStrings( self, 'select the node type', [ 'content', 'link' ] ) as dlg_type:
|
||||
menu = wx.Menu()
|
||||
|
||||
ClientGUIMenus.AppendMenuItem( menu, 'content node', 'A node that parses the given data for content.', self, self.AddContentNode )
|
||||
ClientGUIMenus.AppendMenuItem( menu, 'link node', 'A node that parses the given data for a link, which it then pursues.', self, self.AddLinkNode )
|
||||
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
|
||||
def AddContentNode( self ):
|
||||
|
||||
dlg_title = 'edit content node'
|
||||
|
||||
empty_node = ClientParsing.ParseNodeContent()
|
||||
|
||||
panel_class = EditParseNodeContentPanel
|
||||
|
||||
self.AddNode( dlg_title, empty_node, panel_class )
|
||||
|
||||
|
||||
def AddLinkNode( self ):
|
||||
|
||||
dlg_title = 'edit link node'
|
||||
|
||||
empty_node = ClientParsing.ParseNodeContentLink()
|
||||
|
||||
panel_class = EditParseNodeContentLinkPanel
|
||||
|
||||
self.AddNode( dlg_title, empty_node, panel_class )
|
||||
|
||||
|
||||
def AddNode( self, dlg_title, empty_node, panel_class ):
|
||||
|
||||
with ClientGUITopLevelWindows.DialogEdit( self, dlg_title ) as dlg_edit:
|
||||
|
||||
if dlg_type.ShowModal() == wx.ID_OK:
|
||||
referral_url = self._referral_url_callable()
|
||||
example_data = self._example_data_callable()
|
||||
|
||||
panel = panel_class( dlg_edit, empty_node, referral_url, example_data )
|
||||
|
||||
dlg_edit.SetPanel( panel )
|
||||
|
||||
if dlg_edit.ShowModal() == wx.ID_OK:
|
||||
|
||||
node_type_string = dlg_type.GetString()
|
||||
new_node = panel.GetValue()
|
||||
|
||||
if node_type_string == 'content':
|
||||
|
||||
dlg_title = 'edit content node'
|
||||
|
||||
empty_node = ClientParsing.ParseNodeContent()
|
||||
|
||||
panel_class = EditParseNodeContentPanel
|
||||
|
||||
elif node_type_string == 'link':
|
||||
|
||||
dlg_title = 'edit link node'
|
||||
|
||||
empty_node = ClientParsing.ParseNodeContentLink()
|
||||
|
||||
panel_class = EditParseNodeContentLinkPanel
|
||||
|
||||
( display_tuple, data_tuple ) = self._ConvertNodeToTuples( new_node )
|
||||
|
||||
with ClientGUITopLevelWindows.DialogEdit( self, dlg_title ) as dlg_edit:
|
||||
|
||||
referral_url = self._referral_url_callable()
|
||||
example_data = self._example_data_callable()
|
||||
|
||||
panel = panel_class( dlg_edit, empty_node, referral_url, example_data )
|
||||
|
||||
dlg_edit.SetPanel( panel )
|
||||
|
||||
if dlg_edit.ShowModal() == wx.ID_OK:
|
||||
|
||||
new_node = panel.GetValue()
|
||||
|
||||
( display_tuple, data_tuple ) = self._ConvertNodeToTuples( new_node )
|
||||
|
||||
self._nodes.Append( display_tuple, data_tuple )
|
||||
|
||||
|
||||
self._nodes.Append( display_tuple, data_tuple )
|
||||
|
||||
|
||||
|
||||
|
@ -586,36 +587,6 @@ class EditNodes( wx.Panel ):
|
|||
|
||||
|
||||
|
||||
def EventAdd( self, event ):
|
||||
|
||||
self.Add()
|
||||
|
||||
|
||||
def EventCopy( self, event ):
|
||||
|
||||
self.Copy()
|
||||
|
||||
|
||||
def EventDelete( self, event ):
|
||||
|
||||
self.Delete()
|
||||
|
||||
|
||||
def EventDuplicate( self, event ):
|
||||
|
||||
self.Duplicate()
|
||||
|
||||
|
||||
def EventEdit( self, event ):
|
||||
|
||||
self.Edit()
|
||||
|
||||
|
||||
def EventPaste( self, event ):
|
||||
|
||||
self.Paste()
|
||||
|
||||
|
||||
class EditParseNodeContentPanel( ClientGUIScrolledPanels.EditPanel ):
|
||||
|
||||
def __init__( self, parent, node, referral_url = None, example_data = None ):
|
||||
|
@ -675,8 +646,7 @@ class EditParseNodeContentPanel( ClientGUIScrolledPanels.EditPanel ):
|
|||
|
||||
self._formula_description.Disable()
|
||||
|
||||
self._edit_formula = wx.Button( formula_panel, label = 'edit formula' )
|
||||
self._edit_formula.Bind( wx.EVT_BUTTON, self.EventEditFormula )
|
||||
self._edit_formula = ClientGUICommon.BetterButton( formula_panel, 'edit formula', self.EditFormula )
|
||||
|
||||
#
|
||||
|
||||
|
@ -688,8 +658,7 @@ class EditParseNodeContentPanel( ClientGUIScrolledPanels.EditPanel ):
|
|||
|
||||
self._example_data.SetMinSize( ( -1, 200 ) )
|
||||
|
||||
self._test_parse = wx.Button( test_panel, label = 'test parse' )
|
||||
self._test_parse.Bind( wx.EVT_BUTTON, self.EventTestParse )
|
||||
self._test_parse = ClientGUICommon.BetterButton( test_panel, 'test parse', self.TestParse )
|
||||
|
||||
self._results = ClientGUICommon.SaneMultilineTextCtrl( test_panel )
|
||||
|
||||
|
@ -844,7 +813,7 @@ The 'veto' type will tell the parent panel that this page, while it returned 200
|
|||
self._edit_panel.Layout()
|
||||
|
||||
|
||||
def EventEditFormula( self, event ):
|
||||
def EditFormula( self ):
|
||||
|
||||
dlg_title = 'edit html formula'
|
||||
|
||||
|
@ -865,38 +834,6 @@ The 'veto' type will tell the parent panel that this page, while it returned 200
|
|||
|
||||
|
||||
|
||||
def EventTestParse( self, event ):
|
||||
|
||||
node = self.GetValue()
|
||||
|
||||
try:
|
||||
|
||||
data = self._example_data.GetValue()
|
||||
referral_url = self._referral_url
|
||||
desired_content = 'all'
|
||||
|
||||
results = node.Parse( data, referral_url, desired_content )
|
||||
|
||||
result_lines = [ '*** RESULTS BEGIN ***' ]
|
||||
|
||||
result_lines.extend( ( ClientParsing.ConvertContentResultToPrettyString( result ) for result in results ) )
|
||||
|
||||
result_lines.append( '*** RESULTS END ***' )
|
||||
|
||||
results_text = os.linesep.join( result_lines )
|
||||
|
||||
self._results.SetValue( results_text )
|
||||
|
||||
except Exception as e:
|
||||
|
||||
HydrusData.ShowException( e )
|
||||
|
||||
message = 'Could not parse!'
|
||||
|
||||
wx.MessageBox( message )
|
||||
|
||||
|
||||
|
||||
def GetValue( self ):
|
||||
|
||||
name = self._name.GetValue()
|
||||
|
@ -925,6 +862,38 @@ The 'veto' type will tell the parent panel that this page, while it returned 200
|
|||
return node
|
||||
|
||||
|
||||
def TestParse( self ):
|
||||
|
||||
node = self.GetValue()
|
||||
|
||||
try:
|
||||
|
||||
data = self._example_data.GetValue()
|
||||
referral_url = self._referral_url
|
||||
desired_content = 'all'
|
||||
|
||||
results = node.Parse( data, referral_url, desired_content )
|
||||
|
||||
result_lines = [ '*** RESULTS BEGIN ***' ]
|
||||
|
||||
result_lines.extend( ( ClientParsing.ConvertContentResultToPrettyString( result ) for result in results ) )
|
||||
|
||||
result_lines.append( '*** RESULTS END ***' )
|
||||
|
||||
results_text = os.linesep.join( result_lines )
|
||||
|
||||
self._results.SetValue( results_text )
|
||||
|
||||
except Exception as e:
|
||||
|
||||
HydrusData.ShowException( e )
|
||||
|
||||
message = 'Could not parse!'
|
||||
|
||||
wx.MessageBox( message )
|
||||
|
||||
|
||||
|
||||
class EditParseNodeContentLinkPanel( ClientGUIScrolledPanels.EditPanel ):
|
||||
|
||||
def __init__( self, parent, node, referral_url = None, example_data = None ):
|
||||
|
@ -1554,47 +1523,50 @@ class ManageParsingScriptsPanel( ClientGUIScrolledPanels.ManagePanel ):
|
|||
|
||||
def Add( self ):
|
||||
|
||||
with ClientGUIDialogs.DialogSelectFromListOfStrings( self, 'select the script type', [ 'file metadata lookup' ] ) as dlg_type:
|
||||
menu = wx.Menu()
|
||||
|
||||
ClientGUIMenus.AppendMenuItem( menu, 'file lookup script', 'A script that fetches content for a known file.', self, self.AddFileLookupScript )
|
||||
|
||||
HydrusGlobals.client_controller.PopupMenu( self, menu )
|
||||
|
||||
|
||||
def AddFileLookupScript( self ):
|
||||
|
||||
name = 'new script'
|
||||
url = ''
|
||||
query_type = HC.GET
|
||||
file_identifier_type = ClientParsing.FILE_IDENTIFIER_TYPE_MD5
|
||||
file_identifier_encoding = HC.ENCODING_BASE64
|
||||
file_identifier_arg_name = 'md5'
|
||||
static_args = {}
|
||||
children = []
|
||||
|
||||
dlg_title = 'edit file metadata lookup script'
|
||||
|
||||
empty_script = ClientParsing.ParseRootFileLookup( name, url = url, query_type = query_type, file_identifier_type = file_identifier_type, file_identifier_encoding = file_identifier_encoding, file_identifier_arg_name = file_identifier_arg_name, static_args = static_args, children = children)
|
||||
|
||||
panel_class = EditParsingScriptFileLookupPanel
|
||||
|
||||
self.AddScript( dlg_title, empty_script, panel_class )
|
||||
|
||||
|
||||
def AddScript( self, dlg_title, empty_script, panel_class ):
|
||||
|
||||
with ClientGUITopLevelWindows.DialogEdit( self, dlg_title ) as dlg_edit:
|
||||
|
||||
if dlg_type.ShowModal() == wx.ID_OK:
|
||||
panel = panel_class( dlg_edit, empty_script )
|
||||
|
||||
dlg_edit.SetPanel( panel )
|
||||
|
||||
if dlg_edit.ShowModal() == wx.ID_OK:
|
||||
|
||||
script_type_string = dlg_type.GetString()
|
||||
new_script = panel.GetValue()
|
||||
|
||||
if script_type_string == 'file metadata lookup':
|
||||
|
||||
name = 'new script'
|
||||
url = ''
|
||||
query_type = HC.GET
|
||||
file_identifier_type = ClientParsing.FILE_IDENTIFIER_TYPE_MD5
|
||||
file_identifier_encoding = HC.ENCODING_BASE64
|
||||
file_identifier_arg_name = 'md5'
|
||||
static_args = {}
|
||||
children = []
|
||||
|
||||
empty_script = ClientParsing.ParseRootFileLookup( name, url = url, query_type = query_type, file_identifier_type = file_identifier_type, file_identifier_encoding = file_identifier_encoding, file_identifier_arg_name = file_identifier_arg_name, static_args = static_args, children = children)
|
||||
|
||||
dlg_title = 'edit file metadata lookup script'
|
||||
|
||||
panel_class = EditParsingScriptFileLookupPanel
|
||||
|
||||
self._SetNonDupeName( new_script )
|
||||
|
||||
with ClientGUITopLevelWindows.DialogEdit( self, dlg_title ) as dlg_edit:
|
||||
|
||||
panel = panel_class( dlg_edit, empty_script )
|
||||
|
||||
dlg_edit.SetPanel( panel )
|
||||
|
||||
if dlg_edit.ShowModal() == wx.ID_OK:
|
||||
|
||||
new_script = panel.GetValue()
|
||||
|
||||
self._SetNonDupeName( new_script )
|
||||
|
||||
( display_tuple, data_tuple ) = self._ConvertScriptToTuples( new_script )
|
||||
|
||||
self._scripts.Append( display_tuple, data_tuple )
|
||||
|
||||
|
||||
( display_tuple, data_tuple ) = self._ConvertScriptToTuples( new_script )
|
||||
|
||||
self._scripts.Append( display_tuple, data_tuple )
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -2383,11 +2383,22 @@ class ManageOptionsPanel( ManagePanel ):
|
|||
|
||||
self._apply_all_parents_to_all_services = wx.CheckBox( general_panel )
|
||||
|
||||
#
|
||||
|
||||
suggested_tags_panel = ClientGUICommon.StaticBox( self, 'suggested tags' )
|
||||
|
||||
self._suggested_tags_width = ClientGUICommon.NoneableSpinCtrl( suggested_tags_panel, 'width of suggested tags control', min = 20, none_phrase = 'width of longest tag', unit = 'pixels' )
|
||||
self._suggested_tags_width = wx.SpinCtrl( suggested_tags_panel, min = 20, max = 65535 )
|
||||
|
||||
suggested_tags_favourites_panel = ClientGUICommon.StaticBox( suggested_tags_panel, 'favourites' )
|
||||
self._suggested_tags_layout = ClientGUICommon.BetterChoice( suggested_tags_panel )
|
||||
|
||||
self._suggested_tags_layout.Append( 'notebook', 'notebook' )
|
||||
self._suggested_tags_layout.Append( 'side-by-side', 'columns' )
|
||||
|
||||
suggest_tags_panel_notebook = wx.Notebook( suggested_tags_panel )
|
||||
|
||||
#
|
||||
|
||||
suggested_tags_favourites_panel = wx.Panel( suggest_tags_panel_notebook )
|
||||
|
||||
suggested_tags_favourites_panel.SetMinSize( ( 400, -1 ) )
|
||||
|
||||
|
@ -2412,17 +2423,34 @@ class ManageOptionsPanel( ManagePanel ):
|
|||
|
||||
self._suggested_favourites_input = ClientGUIACDropdown.AutoCompleteDropdownTagsWrite( suggested_tags_favourites_panel, self._suggested_favourites.AddTags, expand_parents, CC.LOCAL_FILE_SERVICE_KEY, CC.LOCAL_TAG_SERVICE_KEY )
|
||||
|
||||
suggested_tags_related_panel = ClientGUICommon.StaticBox( suggested_tags_panel, 'related' )
|
||||
#
|
||||
|
||||
suggested_tags_related_panel = wx.Panel( suggest_tags_panel_notebook )
|
||||
|
||||
self._show_related_tags = wx.CheckBox( suggested_tags_related_panel )
|
||||
|
||||
self._related_tags_width = wx.SpinCtrl( suggested_tags_related_panel, min = 60, max = 400 )
|
||||
|
||||
self._related_tags_search_1_duration_ms = wx.SpinCtrl( suggested_tags_related_panel, min = 50, max = 60000 )
|
||||
self._related_tags_search_2_duration_ms = wx.SpinCtrl( suggested_tags_related_panel, min = 50, max = 60000 )
|
||||
self._related_tags_search_3_duration_ms = wx.SpinCtrl( suggested_tags_related_panel, min = 50, max = 60000 )
|
||||
|
||||
suggested_tags_recent_panel = ClientGUICommon.StaticBox( suggested_tags_panel, 'recent' )
|
||||
#
|
||||
|
||||
suggested_tags_file_lookup_script_panel = wx.Panel( suggest_tags_panel_notebook )
|
||||
|
||||
self._show_file_lookup_script_tags = wx.CheckBox( suggested_tags_file_lookup_script_panel )
|
||||
|
||||
self._favourite_file_lookup_script = ClientGUICommon.BetterChoice( suggested_tags_file_lookup_script_panel )
|
||||
|
||||
script_names = HydrusGlobals.client_controller.Read( 'serialisable_names', HydrusSerialisable.SERIALISABLE_TYPE_PARSE_ROOT_FILE_LOOKUP )
|
||||
|
||||
for name in script_names:
|
||||
|
||||
self._favourite_file_lookup_script.Append( name, name )
|
||||
|
||||
|
||||
#
|
||||
|
||||
suggested_tags_recent_panel = wx.Panel( suggest_tags_panel_notebook )
|
||||
|
||||
self._num_recent_tags = ClientGUICommon.NoneableSpinCtrl( suggested_tags_recent_panel, 'number of recent tags to show', min = 1, none_phrase = 'do not show' )
|
||||
|
||||
|
@ -2458,18 +2486,22 @@ class ManageOptionsPanel( ManagePanel ):
|
|||
|
||||
self._apply_all_parents_to_all_services.SetValue( self._new_options.GetBoolean( 'apply_all_parents_to_all_services' ) )
|
||||
|
||||
self._suggested_tags_width.SetValue( self._new_options.GetNoneableInteger( 'suggested_tags_width' ) )
|
||||
self._suggested_tags_width.SetValue( self._new_options.GetInteger( 'suggested_tags_width' ) )
|
||||
|
||||
self._suggested_tags_layout.SelectClientData( self._new_options.GetNoneableString( 'suggested_tags_layout' ) )
|
||||
|
||||
self._suggested_favourites_services.SelectClientData( CC.LOCAL_TAG_SERVICE_KEY )
|
||||
|
||||
self._show_related_tags.SetValue( self._new_options.GetBoolean( 'show_related_tags' ) )
|
||||
|
||||
self._related_tags_width.SetValue( self._new_options.GetInteger( 'related_tags_width' ) )
|
||||
|
||||
self._related_tags_search_1_duration_ms.SetValue( self._new_options.GetInteger( 'related_tags_search_1_duration_ms' ) )
|
||||
self._related_tags_search_2_duration_ms.SetValue( self._new_options.GetInteger( 'related_tags_search_2_duration_ms' ) )
|
||||
self._related_tags_search_3_duration_ms.SetValue( self._new_options.GetInteger( 'related_tags_search_3_duration_ms' ) )
|
||||
|
||||
self._show_file_lookup_script_tags.SetValue( self._new_options.GetBoolean( 'show_file_lookup_script_tags' ) )
|
||||
|
||||
self._favourite_file_lookup_script.SelectClientData( self._new_options.GetNoneableString( 'favourite_file_lookup_script' ) )
|
||||
|
||||
self._num_recent_tags.SetValue( self._new_options.GetNoneableInteger( 'num_recent_tags' ) )
|
||||
|
||||
#
|
||||
|
@ -2492,28 +2524,72 @@ class ManageOptionsPanel( ManagePanel ):
|
|||
|
||||
#
|
||||
|
||||
suggested_tags_favourites_panel.AddF( self._suggested_favourites_services, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
suggested_tags_favourites_panel.AddF( self._suggested_favourites, CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
suggested_tags_favourites_panel.AddF( self._suggested_favourites_input, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
panel_vbox = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
panel_vbox.AddF( self._suggested_favourites_services, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
panel_vbox.AddF( self._suggested_favourites, CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
panel_vbox.AddF( self._suggested_favourites_input, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
suggested_tags_favourites_panel.SetSizer( panel_vbox )
|
||||
|
||||
#
|
||||
|
||||
panel_vbox = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
rows = []
|
||||
|
||||
rows.append( ( 'Show related tags on single-file manage tags windows: ', self._show_related_tags ) )
|
||||
rows.append( ( 'Width of related tags list: ', self._related_tags_width ) )
|
||||
rows.append( ( 'Initial search duration (ms): ', self._related_tags_search_1_duration_ms ) )
|
||||
rows.append( ( 'Medium search duration (ms): ', self._related_tags_search_2_duration_ms ) )
|
||||
rows.append( ( 'Thorough search duration (ms): ', self._related_tags_search_3_duration_ms ) )
|
||||
|
||||
related_gridbox = ClientGUICommon.WrapInGrid( suggested_tags_related_panel, rows )
|
||||
gridbox = ClientGUICommon.WrapInGrid( suggested_tags_related_panel, rows )
|
||||
|
||||
suggested_tags_related_panel.AddF( related_gridbox, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
panel_vbox.AddF( gridbox, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
suggested_tags_recent_panel.AddF( self._num_recent_tags, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
suggested_tags_related_panel.SetSizer( panel_vbox )
|
||||
|
||||
suggested_tags_panel.AddF( self._suggested_tags_width, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
suggested_tags_panel.AddF( suggested_tags_favourites_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
suggested_tags_panel.AddF( suggested_tags_related_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
suggested_tags_panel.AddF( suggested_tags_recent_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
#
|
||||
|
||||
panel_vbox = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
rows = []
|
||||
|
||||
rows.append( ( 'Show file lookup scripts on single-file manage tags windows: ', self._show_file_lookup_script_tags ) )
|
||||
rows.append( ( 'Favourite file lookup script: ', self._favourite_file_lookup_script ) )
|
||||
|
||||
gridbox = ClientGUICommon.WrapInGrid( suggested_tags_file_lookup_script_panel, rows )
|
||||
|
||||
panel_vbox.AddF( gridbox, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
suggested_tags_file_lookup_script_panel.SetSizer( panel_vbox )
|
||||
|
||||
#
|
||||
|
||||
panel_vbox = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
panel_vbox.AddF( self._num_recent_tags, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
suggested_tags_recent_panel.SetSizer( panel_vbox )
|
||||
|
||||
#
|
||||
|
||||
suggest_tags_panel_notebook.AddPage( suggested_tags_favourites_panel, 'favourites' )
|
||||
suggest_tags_panel_notebook.AddPage( suggested_tags_related_panel, 'related' )
|
||||
suggest_tags_panel_notebook.AddPage( suggested_tags_file_lookup_script_panel, 'file lookup scripts' )
|
||||
suggest_tags_panel_notebook.AddPage( suggested_tags_recent_panel, 'recent' )
|
||||
|
||||
#
|
||||
|
||||
rows = []
|
||||
|
||||
rows.append( ( 'Width of suggested tags columns: ', self._suggested_tags_width ) )
|
||||
rows.append( ( 'Column layout: ', self._suggested_tags_layout ) )
|
||||
|
||||
gridbox = ClientGUICommon.WrapInGrid( suggested_tags_panel, rows )
|
||||
|
||||
suggested_tags_panel.AddF( gridbox, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
suggested_tags_panel.AddF( suggest_tags_panel_notebook, CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
|
||||
vbox.AddF( suggested_tags_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
|
||||
|
@ -2564,7 +2640,8 @@ class ManageOptionsPanel( ManagePanel ):
|
|||
|
||||
self._new_options.SetKey( 'default_tag_service_search_page', self._default_tag_service_search_page.GetChoice() )
|
||||
|
||||
self._new_options.SetNoneableInteger( 'suggested_tags_width', self._suggested_tags_width.GetValue() )
|
||||
self._new_options.SetInteger( 'suggested_tags_width', self._suggested_tags_width.GetValue() )
|
||||
self._new_options.SetNoneableString( 'suggested_tags_layout', self._suggested_tags_layout.GetChoice() )
|
||||
|
||||
self._new_options.SetBoolean( 'apply_all_parents_to_all_services', self._apply_all_parents_to_all_services.GetValue() )
|
||||
|
||||
|
@ -2577,12 +2654,13 @@ class ManageOptionsPanel( ManagePanel ):
|
|||
|
||||
self._new_options.SetBoolean( 'show_related_tags', self._show_related_tags.GetValue() )
|
||||
|
||||
self._new_options.SetInteger( 'related_tags_width', self._related_tags_width.GetValue() )
|
||||
|
||||
self._new_options.SetInteger( 'related_tags_search_1_duration_ms', self._related_tags_search_1_duration_ms.GetValue() )
|
||||
self._new_options.SetInteger( 'related_tags_search_2_duration_ms', self._related_tags_search_2_duration_ms.GetValue() )
|
||||
self._new_options.SetInteger( 'related_tags_search_3_duration_ms', self._related_tags_search_3_duration_ms.GetValue() )
|
||||
|
||||
self._new_options.SetBoolean( 'show_file_lookup_script_tags', self._show_file_lookup_script_tags.GetValue() )
|
||||
self._new_options.SetNoneableString( 'favourite_file_lookup_script', self._favourite_file_lookup_script.GetChoice() )
|
||||
|
||||
self._new_options.SetNoneableInteger( 'num_recent_tags', self._num_recent_tags.GetValue() )
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import ClientConstants as CC
|
||||
import ClientData
|
||||
import ClientGUICommon
|
||||
import ClientGUIDialogs
|
||||
import ClientParsing
|
||||
import ClientSearch
|
||||
import collections
|
||||
import HydrusConstants as HC
|
||||
import HydrusGlobals
|
||||
import HydrusSerialisable
|
||||
import wx
|
||||
|
||||
class ListBoxTagsSuggestionsFavourites( ClientGUICommon.ListBoxTagsStrings ):
|
||||
|
@ -15,6 +18,13 @@ class ListBoxTagsSuggestionsFavourites( ClientGUICommon.ListBoxTagsStrings ):
|
|||
|
||||
self._activate_callable = activate_callable
|
||||
|
||||
width = HydrusGlobals.client_controller.GetNewOptions().GetInteger( 'suggested_tags_width' )
|
||||
|
||||
if width is not None:
|
||||
|
||||
self.SetMinSize( ( width, -1 ) )
|
||||
|
||||
|
||||
|
||||
def _Activate( self ):
|
||||
|
||||
|
@ -25,12 +35,13 @@ class ListBoxTagsSuggestionsFavourites( ClientGUICommon.ListBoxTagsStrings ):
|
|||
self._activate_callable( tags )
|
||||
|
||||
|
||||
|
||||
'''
|
||||
# Maybe reinclude this if per-column autoresizing is desired and not completely buggy
|
||||
def SetTags( self, tags ):
|
||||
|
||||
ClientGUICommon.ListBoxTagsStrings.SetTags( self, tags )
|
||||
|
||||
width = HydrusGlobals.client_controller.GetNewOptions().GetNoneableInteger( 'suggested_tags_width' )
|
||||
width = HydrusGlobals.client_controller.GetNewOptions().GetInteger( 'suggested_tags_width' )
|
||||
|
||||
if width is None:
|
||||
|
||||
|
@ -52,7 +63,7 @@ class ListBoxTagsSuggestionsFavourites( ClientGUICommon.ListBoxTagsStrings ):
|
|||
|
||||
wx.PostEvent( self.GetParent(), CC.SizeChangedEvent( -1 ) )
|
||||
|
||||
|
||||
'''
|
||||
class ListBoxTagsSuggestionsRelated( ClientGUICommon.ListBoxTags ):
|
||||
|
||||
def __init__( self, parent, activate_callable ):
|
||||
|
@ -61,9 +72,9 @@ class ListBoxTagsSuggestionsRelated( ClientGUICommon.ListBoxTags ):
|
|||
|
||||
self._activate_callable = activate_callable
|
||||
|
||||
width = HydrusGlobals.client_controller.GetNewOptions().GetInteger( 'related_tags_width' )
|
||||
width = HydrusGlobals.client_controller.GetNewOptions().GetInteger( 'suggested_tags_width' )
|
||||
|
||||
self.SetMinSize( ( 200, -1 ) )
|
||||
self.SetMinSize( ( width, -1 ) )
|
||||
|
||||
|
||||
def _Activate( self ):
|
||||
|
@ -242,6 +253,75 @@ class RelatedTagsPanel( wx.Panel ):
|
|||
self._FetchRelatedTags( max_time_to_take )
|
||||
|
||||
|
||||
class FileLookupScriptTagsPanel( wx.Panel ):
|
||||
|
||||
def __init__( self, parent, service_key, media, activate_callable ):
|
||||
|
||||
wx.Panel.__init__( self, parent )
|
||||
|
||||
self._service_key = service_key
|
||||
self._media = media
|
||||
|
||||
scripts = HydrusGlobals.client_controller.Read( 'serialisable_named', HydrusSerialisable.SERIALISABLE_TYPE_PARSE_ROOT_FILE_LOOKUP )
|
||||
|
||||
self._script_choice = ClientGUICommon.BetterChoice( self )
|
||||
|
||||
for script in scripts:
|
||||
|
||||
self._script_choice.Append( script.GetName(), script )
|
||||
|
||||
|
||||
new_options = HydrusGlobals.client_controller.GetNewOptions()
|
||||
|
||||
favourite_file_lookup_script = new_options.GetNoneableString( 'favourite_file_lookup_script' )
|
||||
|
||||
self._script_choice.SelectClientData( favourite_file_lookup_script )
|
||||
|
||||
fetch_button = ClientGUICommon.BetterButton( self, 'fetch tags', self.FetchTags )
|
||||
|
||||
self._tags = ListBoxTagsSuggestionsFavourites( self, activate_callable, sort_tags = True )
|
||||
|
||||
vbox = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
vbox.AddF( self._script_choice, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
vbox.AddF( fetch_button, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
vbox.AddF( self._tags, CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
|
||||
self.SetSizer( vbox )
|
||||
|
||||
|
||||
def FetchTags( self ):
|
||||
|
||||
script = self._script_choice.GetChoice()
|
||||
|
||||
if script.UsesUserInput():
|
||||
|
||||
message = 'Enter the custom input for the file lookup script.'
|
||||
|
||||
with ClientGUIDialogs.DialogTextEntry( self, message ) as dlg:
|
||||
|
||||
if dlg.ShowModal() != wx.ID_OK:
|
||||
|
||||
return
|
||||
|
||||
|
||||
file_identifier = dlg.GetValue()
|
||||
|
||||
|
||||
else:
|
||||
|
||||
( m, ) = self._media
|
||||
|
||||
file_identifier = script.ConvertMediaToFileIdentifier( m )
|
||||
|
||||
|
||||
content_results = script.DoQuery( file_identifier, 'all' )
|
||||
|
||||
tags = ClientParsing.GetTagsFromContentResults( content_results )
|
||||
|
||||
self._tags.SetTags( tags )
|
||||
|
||||
|
||||
class SuggestedTagsPanel( wx.Panel ):
|
||||
|
||||
def __init__( self, parent, service_key, media, activate_callable, canvas_key = None ):
|
||||
|
@ -254,44 +334,79 @@ class SuggestedTagsPanel( wx.Panel ):
|
|||
|
||||
self._new_options = HydrusGlobals.client_controller.GetNewOptions()
|
||||
|
||||
something_to_show = False
|
||||
layout_mode = self._new_options.GetNoneableString( 'suggested_tags_layout' )
|
||||
|
||||
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
||||
if layout_mode == 'notebook':
|
||||
|
||||
notebook = wx.Notebook( self )
|
||||
|
||||
panel_parent = notebook
|
||||
|
||||
else:
|
||||
|
||||
panel_parent = self
|
||||
|
||||
|
||||
panels = []
|
||||
|
||||
favourites = self._new_options.GetSuggestedTagsFavourites( service_key )
|
||||
|
||||
if len( favourites ) > 0:
|
||||
|
||||
favourite_tags = ListBoxTagsSuggestionsFavourites( self, activate_callable )
|
||||
favourite_tags = ListBoxTagsSuggestionsFavourites( panel_parent, activate_callable )
|
||||
|
||||
favourite_tags.SetTags( favourites )
|
||||
|
||||
hbox.AddF( favourite_tags, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
something_to_show = True
|
||||
panels.append( ( 'favourites', favourite_tags ) )
|
||||
|
||||
|
||||
if self._new_options.GetBoolean( 'show_related_tags' ) and len( media ) == 1:
|
||||
|
||||
related_tags = RelatedTagsPanel( self, service_key, media, activate_callable, canvas_key = self._canvas_key )
|
||||
related_tags = RelatedTagsPanel( panel_parent, service_key, media, activate_callable, canvas_key = self._canvas_key )
|
||||
|
||||
hbox.AddF( related_tags, CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
panels.append( ( 'related', related_tags ) )
|
||||
|
||||
something_to_show = True
|
||||
|
||||
if self._new_options.GetBoolean( 'show_file_lookup_script_tags' ) and len( media ) == 1:
|
||||
|
||||
file_lookup_script_tags = FileLookupScriptTagsPanel( panel_parent, service_key, media, activate_callable )
|
||||
|
||||
panels.append( ( 'file lookup scripts', file_lookup_script_tags ) )
|
||||
|
||||
|
||||
if self._new_options.GetNoneableInteger( 'num_recent_tags' ) is not None:
|
||||
|
||||
recent_tags = RecentTagsPanel( self, service_key, activate_callable, canvas_key = self._canvas_key )
|
||||
recent_tags = RecentTagsPanel( panel_parent, service_key, activate_callable, canvas_key = self._canvas_key )
|
||||
|
||||
hbox.AddF( recent_tags, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
something_to_show = True
|
||||
panels.append( ( 'recent', recent_tags ) )
|
||||
|
||||
|
||||
self.SetSizer( hbox )
|
||||
if layout_mode == 'notebook':
|
||||
|
||||
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
for ( name, panel ) in panels:
|
||||
|
||||
notebook.AddPage( panel, name )
|
||||
|
||||
|
||||
hbox.AddF( notebook, CC.FLAGS_EXPAND_BOTH_WAYS )
|
||||
|
||||
self.SetSizer( hbox )
|
||||
|
||||
elif layout_mode == 'columns':
|
||||
|
||||
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
for ( name, panel ) in panels:
|
||||
|
||||
hbox.AddF( panel, CC.FLAGS_EXPAND_PERPENDICULAR )
|
||||
|
||||
|
||||
self.SetSizer( hbox )
|
||||
|
||||
|
||||
if not something_to_show:
|
||||
if len( panels ) == 0:
|
||||
|
||||
self.Hide()
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@ import bs4
|
|||
import ClientNetworking
|
||||
import HydrusConstants as HC
|
||||
import HydrusData
|
||||
import HydrusExceptions
|
||||
import HydrusGlobals
|
||||
import HydrusSerialisable
|
||||
import HydrusTags
|
||||
import os
|
||||
|
@ -87,6 +89,22 @@ def GetChildrenContent( children, data, referral_url, desired_content ):
|
|||
|
||||
return content
|
||||
|
||||
def GetTagsFromContentResults( results ):
|
||||
|
||||
tag_results = []
|
||||
|
||||
for ( ( name, content_type, additional_info ), parsed_text ) in results:
|
||||
|
||||
if content_type == HC.CONTENT_TYPE_MAPPINGS:
|
||||
|
||||
tag_results.append( HydrusTags.CombineTag( additional_info, parsed_text ) )
|
||||
|
||||
|
||||
|
||||
tag_results = HydrusTags.CleanTags( tag_results )
|
||||
|
||||
return tag_results
|
||||
|
||||
def GetVetoes( parsed_texts, additional_info ):
|
||||
|
||||
( veto_if_matches_found, match_if_text_present, search_text ) = additional_info
|
||||
|
@ -460,7 +478,9 @@ class ParseNodeContentLink( HydrusSerialisable.SerialisableBase ):
|
|||
|
||||
response = ClientNetworking.RequestsGet( search_url, headers = headers )
|
||||
|
||||
children_content = GetChildrenContent( self._children, data, search_url, desired_content )
|
||||
linked_data = response.content
|
||||
|
||||
children_content = GetChildrenContent( self._children, linked_data, search_url, desired_content )
|
||||
|
||||
content.extend( children_content )
|
||||
|
||||
|
@ -542,6 +562,64 @@ class ParseRootFileLookup( HydrusSerialisable.SerialisableBaseNamed ):
|
|||
self._children = [ HydrusSerialisable.CreateFromSerialisableTuple( serialisable_child ) for serialisable_child in serialisable_children ]
|
||||
|
||||
|
||||
def ConvertMediaToFileIdentifier( self, media ):
|
||||
|
||||
if self._file_identifier_type == FILE_IDENTIFIER_TYPE_USER_INPUT:
|
||||
|
||||
raise Exception( 'Cannot convert media to file identifier--this script takes user input!' )
|
||||
|
||||
elif self._file_identifier_type == FILE_IDENTIFIER_TYPE_SHA256:
|
||||
|
||||
return media.GetHash()
|
||||
|
||||
elif self._file_identifier_type in ( FILE_IDENTIFIER_TYPE_MD5, FILE_IDENTIFIER_TYPE_SHA1, FILE_IDENTIFIER_TYPE_SHA512 ):
|
||||
|
||||
sha256_hash = media.GetHash()
|
||||
|
||||
if self._file_identifier_type == FILE_IDENTIFIER_TYPE_MD5:
|
||||
|
||||
hash_type = 'md5'
|
||||
|
||||
elif self._file_identifier_type == FILE_IDENTIFIER_TYPE_SHA1:
|
||||
|
||||
hash_type = 'sha1'
|
||||
|
||||
elif self._file_identifier_type == FILE_IDENTIFIER_TYPE_SHA512:
|
||||
|
||||
hash_type = 'sha512'
|
||||
|
||||
|
||||
try:
|
||||
|
||||
( other_hash, ) = HydrusGlobals.client_controller.Read( 'file_hashes', ( sha256_hash, ), 'sha256', hash_type )
|
||||
|
||||
return other_hash
|
||||
|
||||
except:
|
||||
|
||||
raise Exception( 'I do not know that file\'s ' + hash_type + ' hash, so I cannot look it up!' )
|
||||
|
||||
|
||||
elif self._file_identifier_type == FILE_IDENTIFIER_TYPE_FILE:
|
||||
|
||||
hash = media.GetHash()
|
||||
mime = media.GetMime()
|
||||
|
||||
client_files_manager = HydrusGlobals.client_controller.GetClientFilesManager()
|
||||
|
||||
try:
|
||||
|
||||
path = client_files_manager.GetFilePath( hash, mime )
|
||||
|
||||
return path
|
||||
|
||||
except HydrusExceptions.FileMissingException as e:
|
||||
|
||||
raise Exception( 'That file is not in the database\'s local files, so I cannot look it up!' )
|
||||
|
||||
|
||||
|
||||
|
||||
def FetchData( self, file_identifier ):
|
||||
|
||||
request_args = dict( self._static_args )
|
||||
|
@ -602,9 +680,9 @@ class ParseRootFileLookup( HydrusSerialisable.SerialisableBaseNamed ):
|
|||
return self.Parse( data, desired_content )
|
||||
|
||||
|
||||
def GetFileIdentifier( self ):
|
||||
def UsesUserInput( self ):
|
||||
|
||||
return ( self._file_identifier_type, self._file_identifier_encoding )
|
||||
return self._file_identifier_type == FILE_IDENTIFIER_TYPE_USER_INPUT
|
||||
|
||||
|
||||
def Parse( self, data, desired_content ):
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
import ClientImageHandling
|
||||
import cv2
|
||||
import HydrusSerialisable
|
||||
import numpy
|
||||
import struct
|
||||
|
||||
def DumpToPng( payload, title, payload_type, text, path ):
|
||||
|
||||
payload_length = len( payload )
|
||||
|
||||
payload_string_length = payload_length + 4
|
||||
|
||||
square_width = int( float( payload_string_length ) ** 0.5 )
|
||||
|
||||
width = max( 512, square_width )
|
||||
|
||||
payload_height = float( payload_string_length ) / width
|
||||
|
||||
if float( payload_string_length ) / width % 1.0 > 0:
|
||||
|
||||
payload_height += 1
|
||||
|
||||
|
||||
# given this width, figure out how much height we need for title and text and object type
|
||||
# does cv have gettextentent or similar?
|
||||
# getTextSize looks like the one
|
||||
# intelligently wrap the text to fit into our width sans padding
|
||||
|
||||
# we now know our height
|
||||
top_height = 250
|
||||
|
||||
top_image = numpy.empty( ( top_height, width ), dtype = 'uint8' )
|
||||
|
||||
top_image.fill( 255 )
|
||||
|
||||
# draw hydrus icon in the corner
|
||||
# draw title
|
||||
# draw payload_type
|
||||
# draw text
|
||||
top_height_header = struct.pack( '!H', top_height )
|
||||
|
||||
( byte0, byte1 ) = top_height_header
|
||||
|
||||
top_image[0][0] = ord( byte0 )
|
||||
top_image[0][1] = ord( byte1 )
|
||||
|
||||
payload_length_header = struct.pack( '!I', payload_length )
|
||||
|
||||
num_empty_bytes = payload_height * width - payload_string_length
|
||||
|
||||
full_payload_string = payload_length_header + payload + '\x00' * num_empty_bytes
|
||||
|
||||
payload_image = numpy.fromstring( full_payload_string, dtype = 'uint8' ).reshape( ( payload_height, width ) )
|
||||
|
||||
# if this works out wrong, you can change axis or do stack_vertically instead or something. one of those will do the trick
|
||||
finished_image = numpy.concatenate( top_image, payload_image )
|
||||
|
||||
# make sure this is how cv 'params' work
|
||||
cv2.imwrite( path, finished_image, params = { cv2.IMWRITE_PNG_COMPRESSION : 9 } )
|
||||
|
||||
def LoadFromPng( path ):
|
||||
|
||||
numpy_image = cv2.imread( path )
|
||||
|
||||
( height, width ) = numpy_image.shape
|
||||
|
||||
complete_data = numpy_image.tostring()
|
||||
|
||||
top_height_header = complete_data[:2]
|
||||
|
||||
( top_height, ) = struct.unpack( '!H', top_height_header )
|
||||
|
||||
full_payload_string = complete_data[ width * top_height : ]
|
||||
|
||||
payload_length_header = full_payload_string[:4]
|
||||
|
||||
( payload_length, ) = struct.unpack( '!I', payload_length_header )
|
||||
|
||||
payload = full_payload_string[ 4 : 4 + payload_length ]
|
||||
|
||||
return payload
|
||||
|
|
@ -44,7 +44,7 @@ options = {}
|
|||
# Misc
|
||||
|
||||
NETWORK_VERSION = 17
|
||||
SOFTWARE_VERSION = 230
|
||||
SOFTWARE_VERSION = 231
|
||||
|
||||
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )
|
||||
|
||||
|
|
|
@ -10,8 +10,6 @@ pubsub_profile_mode = False
|
|||
force_idle_mode = False
|
||||
server_busy = False
|
||||
|
||||
no_focus_changed = False
|
||||
|
||||
do_idle_shutdown_work = False
|
||||
shutdown_complete = False
|
||||
restart = False
|
||||
|
|
|
@ -2,15 +2,15 @@ import HydrusConstants as HC
|
|||
import HydrusData
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
# I am having unreliable problems with stdout on Windows when I launch client.pyw with pythonw.exe, hence the except IOError business
|
||||
# I guess I am sending bad characters or something to the 'windowised' environment of pythonw
|
||||
class HydrusLogger( object ):
|
||||
|
||||
def __init__( self, log_path ):
|
||||
def __init__( self, base_dir, prefix ):
|
||||
|
||||
self._log_path = log_path
|
||||
self._log_path_base = os.path.join( base_dir, prefix )
|
||||
self._lock = threading.Lock()
|
||||
|
||||
|
||||
def __enter__( self ):
|
||||
|
@ -23,14 +23,14 @@ class HydrusLogger( object ):
|
|||
sys.stdout = self
|
||||
sys.stderr = self
|
||||
|
||||
self._log_file = open( self._log_path, 'a' )
|
||||
self._OpenLog()
|
||||
|
||||
return self
|
||||
|
||||
|
||||
def __exit__( self, exc_type, exc_val, exc_tb ):
|
||||
|
||||
self._log_file.close()
|
||||
self._CloseLog()
|
||||
|
||||
sys.stdout = self._previous_sys_stdout
|
||||
sys.stderr = self._previous_sys_stderr
|
||||
|
@ -38,21 +38,61 @@ class HydrusLogger( object ):
|
|||
return False
|
||||
|
||||
|
||||
def _CloseLog( self ):
|
||||
|
||||
self._log_file.close()
|
||||
|
||||
|
||||
def _GetLogPath( self ):
|
||||
|
||||
current_time_struct = time.gmtime()
|
||||
|
||||
( current_year, current_month ) = ( current_time_struct.tm_year, current_time_struct.tm_mon )
|
||||
|
||||
log_path = self._log_path_base + ' - ' + str( current_year ) + '-' + str( current_month ) + '.log'
|
||||
|
||||
return log_path
|
||||
|
||||
|
||||
def _OpenLog( self ):
|
||||
|
||||
self._log_path = self._GetLogPath()
|
||||
|
||||
self._log_file = open( self._log_path, 'a' )
|
||||
|
||||
|
||||
def _SwitchToANewLogFileIfDue( self ):
|
||||
|
||||
correct_log_path = self._GetLogPath()
|
||||
|
||||
if correct_log_path != self._log_path:
|
||||
|
||||
self._CloseLog()
|
||||
|
||||
self._OpenLog()
|
||||
|
||||
|
||||
|
||||
def flush( self ):
|
||||
|
||||
if not self._problem_with_previous_stdout:
|
||||
with self._lock:
|
||||
|
||||
try:
|
||||
if not self._problem_with_previous_stdout:
|
||||
|
||||
self._previous_sys_stdout.flush()
|
||||
|
||||
except IOError:
|
||||
|
||||
self._problem_with_previous_stdout = True
|
||||
try:
|
||||
|
||||
self._previous_sys_stdout.flush()
|
||||
|
||||
except IOError:
|
||||
|
||||
self._problem_with_previous_stdout = True
|
||||
|
||||
|
||||
|
||||
|
||||
self._log_file.flush()
|
||||
self._log_file.flush()
|
||||
|
||||
self._SwitchToANewLogFileIfDue()
|
||||
|
||||
|
||||
|
||||
def isatty( self ):
|
||||
|
@ -62,29 +102,32 @@ class HydrusLogger( object ):
|
|||
|
||||
def write( self, value ):
|
||||
|
||||
if value in ( os.linesep, '\n' ):
|
||||
with self._lock:
|
||||
|
||||
prefix = ''
|
||||
|
||||
else:
|
||||
|
||||
prefix = time.strftime( '%Y/%m/%d %H:%M:%S: ', time.localtime() )
|
||||
|
||||
|
||||
message = HydrusData.ToByteString( prefix + value )
|
||||
|
||||
if not self._problem_with_previous_stdout:
|
||||
|
||||
try:
|
||||
if value in ( os.linesep, '\n' ):
|
||||
|
||||
self._previous_sys_stdout.write( message )
|
||||
prefix = ''
|
||||
|
||||
except IOError:
|
||||
else:
|
||||
|
||||
self._problem_with_previous_stdout = True
|
||||
prefix = time.strftime( '%Y/%m/%d %H:%M:%S: ', time.localtime() )
|
||||
|
||||
|
||||
|
||||
self._log_file.write( message )
|
||||
message = HydrusData.ToByteString( prefix + value )
|
||||
|
||||
if not self._problem_with_previous_stdout:
|
||||
|
||||
try:
|
||||
|
||||
self._previous_sys_stdout.write( message )
|
||||
|
||||
except IOError:
|
||||
|
||||
self._problem_with_previous_stdout = True
|
||||
|
||||
|
||||
|
||||
self._log_file.write( message )
|
||||
|
||||
|
||||
|
|
@ -227,7 +227,7 @@ def FilterFreePaths( paths ):
|
|||
|
||||
except OSError as e: # 'already in use by another process'
|
||||
|
||||
HydrusData.Print( path + ' ' + str( e ) )
|
||||
HydrusData.Print( 'Already in use: ' + path )
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue