hydrus/hydrus/client/ClientOptions.py

1769 lines
74 KiB
Python

import os
import threading
from qtpy import QtGui as QG
from hydrus.core import HydrusConstants as HC
from hydrus.core import HydrusGlobals as HG
from hydrus.core import HydrusData
from hydrus.core import HydrusSerialisable
from hydrus.core import HydrusTags
from hydrus.client import ClientConstants as CC
from hydrus.client import ClientDefaults
from hydrus.client import ClientDuplicates
from hydrus.client.importing.options import FileImportOptions
class ClientOptions( HydrusSerialisable.SerialisableBase ):
SERIALISABLE_TYPE = HydrusSerialisable.SERIALISABLE_TYPE_CLIENT_OPTIONS
SERIALISABLE_NAME = 'Client Options'
SERIALISABLE_VERSION = 5
def __init__( self ):
HydrusSerialisable.SerialisableBase.__init__( self )
self._dictionary = HydrusSerialisable.SerialisableDictionary()
self._lock = threading.Lock()
self._InitialiseDefaults()
def _GetDefaultMediaViewOptions( self ):
media_view = HydrusSerialisable.SerialisableDictionary() # integer keys, so got to be cleverer dict
# media_show_action, media_start_paused, media_start_with_embed, preview_show_action, preview_start_paused, preview_start_with_embed, ( media_scale_up, media_scale_down, preview_scale_up, preview_scale_down, exact_zooms_only, scale_up_quality, scale_down_quality ) )
from hydrus.client.gui.canvas import ClientGUIMPV
if ClientGUIMPV.MPV_IS_AVAILABLE:
video_action = CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV
audio_action = CC.MEDIA_VIEWER_ACTION_SHOW_WITH_MPV
video_zoom_info = ( CC.MEDIA_VIEWER_SCALE_TO_CANVAS, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, False, CC.ZOOM_LANCZOS4, CC.ZOOM_AREA )
else:
video_action = CC.MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE
audio_action = CC.MEDIA_VIEWER_ACTION_SHOW_OPEN_EXTERNALLY_BUTTON
video_zoom_info = ( CC.MEDIA_VIEWER_SCALE_100, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, True, CC.ZOOM_LANCZOS4, CC.ZOOM_AREA )
image_zoom_info = ( CC.MEDIA_VIEWER_SCALE_TO_CANVAS, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, False, CC.ZOOM_LANCZOS4, CC.ZOOM_AREA )
gif_zoom_info = ( CC.MEDIA_VIEWER_SCALE_TO_CANVAS, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, False, CC.ZOOM_LANCZOS4, CC.ZOOM_AREA )
flash_zoom_info = ( CC.MEDIA_VIEWER_SCALE_TO_CANVAS, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, CC.MEDIA_VIEWER_SCALE_TO_CANVAS, False, CC.ZOOM_LINEAR, CC.ZOOM_LINEAR )
null_zoom_info = ( CC.MEDIA_VIEWER_SCALE_100, CC.MEDIA_VIEWER_SCALE_100, CC.MEDIA_VIEWER_SCALE_100, CC.MEDIA_VIEWER_SCALE_100, False, CC.ZOOM_LINEAR, CC.ZOOM_LINEAR )
media_start_paused = False
media_start_with_embed = False
preview_start_paused = False
preview_start_with_embed = False
media_view[ HC.GENERAL_IMAGE ] = ( CC.MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE, media_start_paused, media_start_with_embed, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE, preview_start_paused, preview_start_with_embed, image_zoom_info )
media_view[ HC.GENERAL_ANIMATION ] = ( video_action, media_start_paused, media_start_with_embed, video_action, preview_start_paused, preview_start_with_embed, gif_zoom_info )
media_view[ HC.GENERAL_VIDEO ] = ( video_action, media_start_paused, media_start_with_embed, video_action, preview_start_paused, preview_start_with_embed, video_zoom_info )
media_view[ HC.GENERAL_AUDIO ] = ( audio_action, media_start_paused, media_start_with_embed, audio_action, preview_start_paused, preview_start_with_embed, null_zoom_info )
media_view[ HC.GENERAL_APPLICATION ] = ( CC.MEDIA_VIEWER_ACTION_SHOW_OPEN_EXTERNALLY_BUTTON, media_start_paused, media_start_with_embed, CC.MEDIA_VIEWER_ACTION_SHOW_OPEN_EXTERNALLY_BUTTON, preview_start_paused, preview_start_with_embed, null_zoom_info )
return media_view
def _GetMediaViewOptions( self, mime ):
if mime in self._dictionary[ 'media_view' ]:
return self._dictionary[ 'media_view' ][ mime ]
else:
if mime not in HC.mimes_to_general_mimetypes:
null_result = ( CC.MEDIA_VIEWER_ACTION_DO_NOT_SHOW, False, False, CC.MEDIA_VIEWER_ACTION_DO_NOT_SHOW, False, False, ( CC.MEDIA_VIEWER_SCALE_100, CC.MEDIA_VIEWER_SCALE_100, CC.MEDIA_VIEWER_SCALE_100, CC.MEDIA_VIEWER_SCALE_100, False, CC.ZOOM_LINEAR, CC.ZOOM_LINEAR ) )
return null_result
general_mime_type = HC.mimes_to_general_mimetypes[ mime ]
if general_mime_type not in self._dictionary[ 'media_view' ]:
self._dictionary[ 'media_view' ] = self._GetDefaultMediaViewOptions()
return self._dictionary[ 'media_view' ][ general_mime_type ]
def _GetSerialisableInfo( self ):
serialisable_info = self._dictionary.GetSerialisableTuple()
return serialisable_info
def _InitialiseDefaults( self ):
self._dictionary[ 'booleans' ] = {}
self._dictionary[ 'booleans' ][ 'advanced_mode' ] = False
self._dictionary[ 'booleans' ][ 'filter_inbox_and_archive_predicates' ] = False
self._dictionary[ 'booleans' ][ 'discord_dnd_fix' ] = False
self._dictionary[ 'booleans' ][ 'secret_discord_dnd_fix' ] = False
self._dictionary[ 'booleans' ][ 'disable_cv_for_gifs' ] = False
self._dictionary[ 'booleans' ][ 'show_unmatched_urls_in_media_viewer' ] = False
self._dictionary[ 'booleans' ][ 'set_search_focus_on_page_change' ] = False
self._dictionary[ 'booleans' ][ 'allow_remove_on_manage_tags_input' ] = True
self._dictionary[ 'booleans' ][ 'yes_no_on_remove_on_manage_tags' ] = True
self._dictionary[ 'booleans' ][ 'activate_window_on_tag_search_page_activation' ] = False
self._dictionary[ 'booleans' ][ 'show_related_tags' ] = True
self._dictionary[ 'booleans' ][ 'show_file_lookup_script_tags' ] = False
self._dictionary[ 'booleans' ][ 'freeze_message_manager_when_mouse_on_other_monitor' ] = False
self._dictionary[ 'booleans' ][ 'freeze_message_manager_when_main_gui_minimised' ] = False
self._dictionary[ 'booleans' ][ 'load_images_with_pil' ] = False
self._dictionary[ 'booleans' ][ 'use_system_ffmpeg' ] = False
self._dictionary[ 'booleans' ][ 'elide_page_tab_names' ] = True
self._dictionary[ 'booleans' ][ 'maintain_similar_files_duplicate_pairs_during_idle' ] = False
self._dictionary[ 'booleans' ][ 'show_namespaces' ] = True
self._dictionary[ 'booleans' ][ 'show_number_namespaces' ] = True
self._dictionary[ 'booleans' ][ 'replace_tag_underscores_with_spaces' ] = False
self._dictionary[ 'booleans' ][ 'verify_regular_https' ] = True
self._dictionary[ 'booleans' ][ 'page_drop_chase_normally' ] = True
self._dictionary[ 'booleans' ][ 'page_drop_chase_with_shift' ] = False
self._dictionary[ 'booleans' ][ 'page_drag_change_tab_normally' ] = True
self._dictionary[ 'booleans' ][ 'page_drag_change_tab_with_shift' ] = True
self._dictionary[ 'booleans' ][ 'wheel_scrolls_tab_bar' ] = False
self._dictionary[ 'booleans' ][ 'anchor_and_hide_canvas_drags' ] = HC.PLATFORM_WINDOWS
self._dictionary[ 'booleans' ][ 'touchscreen_canvas_drags_unanchor' ] = False
self._dictionary[ 'booleans' ][ 'import_page_progress_display' ] = True
self._dictionary[ 'booleans' ][ 'process_subs_in_random_order' ] = True
self._dictionary[ 'booleans' ][ 'ac_select_first_with_count' ] = False
self._dictionary[ 'booleans' ][ 'saving_sash_positions_on_exit' ] = True
self._dictionary[ 'booleans' ][ 'file_maintenance_during_idle' ] = True
self._dictionary[ 'booleans' ][ 'file_maintenance_during_active' ] = True
self._dictionary[ 'booleans' ][ 'tag_display_maintenance_during_idle' ] = True
self._dictionary[ 'booleans' ][ 'tag_display_maintenance_during_active' ] = True
self._dictionary[ 'booleans' ][ 'save_page_sort_on_change' ] = False
self._dictionary[ 'booleans' ][ 'force_hide_page_signal_on_new_page' ] = False
self._dictionary[ 'booleans' ][ 'pause_export_folders_sync' ] = False
self._dictionary[ 'booleans' ][ 'pause_import_folders_sync' ] = False
self._dictionary[ 'booleans' ][ 'pause_repo_sync' ] = False
self._dictionary[ 'booleans' ][ 'pause_subs_sync' ] = False
self._dictionary[ 'booleans' ][ 'pause_all_new_network_traffic' ] = False
self._dictionary[ 'booleans' ][ 'boot_with_network_traffic_paused' ] = False
self._dictionary[ 'booleans' ][ 'pause_all_file_queues' ] = False
self._dictionary[ 'booleans' ][ 'pause_all_watcher_checkers' ] = False
self._dictionary[ 'booleans' ][ 'pause_all_gallery_searches' ] = False
self._dictionary[ 'booleans' ][ 'popup_message_force_min_width' ] = False
self._dictionary[ 'booleans' ][ 'always_show_iso_time' ] = False
self._dictionary[ 'booleans' ][ 'confirm_multiple_local_file_services_move' ] = True
self._dictionary[ 'booleans' ][ 'confirm_multiple_local_file_services_copy' ] = True
self._dictionary[ 'booleans' ][ 'use_advanced_file_deletion_dialog' ] = False
self._dictionary[ 'booleans' ][ 'show_new_on_file_seed_short_summary' ] = False
self._dictionary[ 'booleans' ][ 'show_deleted_on_file_seed_short_summary' ] = False
self._dictionary[ 'booleans' ][ 'only_save_last_session_during_idle' ] = False
self._dictionary[ 'booleans' ][ 'do_human_sort_on_hdd_file_import_paths' ] = True
self._dictionary[ 'booleans' ][ 'highlight_new_watcher' ] = True
self._dictionary[ 'booleans' ][ 'highlight_new_query' ] = True
self._dictionary[ 'booleans' ][ 'delete_files_after_export' ] = False
self._dictionary[ 'booleans' ][ 'file_viewing_statistics_active' ] = True
self._dictionary[ 'booleans' ][ 'file_viewing_statistics_active_on_dupe_filter' ] = False
self._dictionary[ 'booleans' ][ 'prefix_hash_when_copying' ] = False
self._dictionary[ 'booleans' ][ 'file_system_waits_on_wakeup' ] = False
self._dictionary[ 'booleans' ][ 'always_show_system_everything' ] = False
self._dictionary[ 'booleans' ][ 'watch_clipboard_for_watcher_urls' ] = False
self._dictionary[ 'booleans' ][ 'watch_clipboard_for_other_recognised_urls' ] = False
self._dictionary[ 'booleans' ][ 'default_search_synchronised' ] = True
self._dictionary[ 'booleans' ][ 'autocomplete_float_main_gui' ] = True
self._dictionary[ 'booleans' ][ 'global_audio_mute' ] = False
self._dictionary[ 'booleans' ][ 'media_viewer_audio_mute' ] = False
self._dictionary[ 'booleans' ][ 'media_viewer_uses_its_own_audio_volume' ] = False
self._dictionary[ 'booleans' ][ 'preview_audio_mute' ] = False
self._dictionary[ 'booleans' ][ 'preview_uses_its_own_audio_volume' ] = True
self._dictionary[ 'booleans' ][ 'always_loop_gifs' ] = True
self._dictionary[ 'booleans' ][ 'always_show_system_tray_icon' ] = False
self._dictionary[ 'booleans' ][ 'minimise_client_to_system_tray' ] = False
self._dictionary[ 'booleans' ][ 'close_client_to_system_tray' ] = False
self._dictionary[ 'booleans' ][ 'start_client_in_system_tray' ] = False
self._dictionary[ 'booleans' ][ 'use_qt_file_dialogs' ] = False
self._dictionary[ 'booleans' ][ 'notify_client_api_cookies' ] = False
self._dictionary[ 'booleans' ][ 'expand_parents_on_storage_taglists' ] = True
self._dictionary[ 'booleans' ][ 'expand_parents_on_storage_autocomplete_taglists' ] = True
self._dictionary[ 'booleans' ][ 'show_parent_decorators_on_storage_taglists' ] = True
self._dictionary[ 'booleans' ][ 'show_parent_decorators_on_storage_autocomplete_taglists' ] = True
self._dictionary[ 'booleans' ][ 'show_sibling_decorators_on_storage_taglists' ] = True
self._dictionary[ 'booleans' ][ 'show_sibling_decorators_on_storage_autocomplete_taglists' ] = True
self._dictionary[ 'booleans' ][ 'show_session_size_warnings' ] = True
self._dictionary[ 'booleans' ][ 'delete_lock_for_archived_files' ] = False
self._dictionary[ 'booleans' ][ 'remember_last_advanced_file_deletion_reason' ] = True
self._dictionary[ 'booleans' ][ 'remember_last_advanced_file_deletion_special_action' ] = False
self._dictionary[ 'booleans' ][ 'do_macos_debug_dialog_menus' ] = True
self._dictionary[ 'booleans' ][ 'save_default_tag_service_tab_on_change' ] = True
self._dictionary[ 'booleans' ][ 'force_animation_scanbar_show' ] = False
self._dictionary[ 'booleans' ][ 'call_mouse_buttons_primary_secondary' ] = False
self._dictionary[ 'booleans' ][ 'start_note_editing_at_end' ] = True
self._dictionary[ 'booleans' ][ 'menu_choice_buttons_can_mouse_scroll' ] = True
self._dictionary[ 'booleans' ][ 'focus_preview_on_ctrl_click' ] = False
self._dictionary[ 'booleans' ][ 'focus_preview_on_ctrl_click_only_static' ] = False
self._dictionary[ 'booleans' ][ 'focus_preview_on_shift_click' ] = False
self._dictionary[ 'booleans' ][ 'focus_preview_on_shift_click_only_static' ] = False
#
self._dictionary[ 'colours' ] = HydrusSerialisable.SerialisableDictionary()
self._dictionary[ 'colours' ][ 'default' ] = HydrusSerialisable.SerialisableDictionary()
self._dictionary[ 'colours' ][ 'default' ][ CC.COLOUR_THUMB_BACKGROUND ] = ( 255, 255, 255 )
self._dictionary[ 'colours' ][ 'default' ][ CC.COLOUR_THUMB_BACKGROUND_SELECTED ] = ( 217, 242, 255 ) # light blue
self._dictionary[ 'colours' ][ 'default' ][ CC.COLOUR_THUMB_BACKGROUND_REMOTE ] = ( 32, 32, 36 ) # 50% Payne's Gray
self._dictionary[ 'colours' ][ 'default' ][ CC.COLOUR_THUMB_BACKGROUND_REMOTE_SELECTED ] = ( 64, 64, 72 ) # Payne's Gray
self._dictionary[ 'colours' ][ 'default' ][ CC.COLOUR_THUMB_BORDER ] = ( 223, 227, 230 ) # light grey
self._dictionary[ 'colours' ][ 'default' ][ CC.COLOUR_THUMB_BORDER_SELECTED ] = ( 1, 17, 26 ) # dark grey
self._dictionary[ 'colours' ][ 'default' ][ CC.COLOUR_THUMB_BORDER_REMOTE ] = ( 248, 208, 204 ) # 25% Vermillion, 75% White
self._dictionary[ 'colours' ][ 'default' ][ CC.COLOUR_THUMB_BORDER_REMOTE_SELECTED ] = ( 227, 66, 52 ) # Vermillion, lol
self._dictionary[ 'colours' ][ 'default' ][ CC.COLOUR_THUMBGRID_BACKGROUND ] = ( 255, 255, 255 )
self._dictionary[ 'colours' ][ 'default' ][ CC.COLOUR_AUTOCOMPLETE_BACKGROUND ] = ( 235, 248, 255 ) # very light blue
self._dictionary[ 'colours' ][ 'default' ][ CC.COLOUR_MEDIA_BACKGROUND ] = ( 255, 255, 255 )
self._dictionary[ 'colours' ][ 'default' ][ CC.COLOUR_MEDIA_TEXT ] = ( 0, 0, 0 )
self._dictionary[ 'colours' ][ 'default' ][ CC.COLOUR_TAGS_BOX ] = ( 255, 255, 255 )
self._dictionary[ 'colours' ][ 'darkmode' ] = HydrusSerialisable.SerialisableDictionary()
self._dictionary[ 'colours' ][ 'darkmode' ][ CC.COLOUR_THUMB_BACKGROUND ] = ( 64, 64, 72 ) # Payne's Gray
self._dictionary[ 'colours' ][ 'darkmode' ][ CC.COLOUR_THUMB_BACKGROUND_SELECTED ] = ( 112, 128, 144 ) # Slate Gray
self._dictionary[ 'colours' ][ 'darkmode' ][ CC.COLOUR_THUMB_BACKGROUND_REMOTE ] = ( 64, 13, 2 ) # Black Bean
self._dictionary[ 'colours' ][ 'darkmode' ][ CC.COLOUR_THUMB_BACKGROUND_REMOTE_SELECTED ] = ( 171, 39, 79 ) # Amaranth Purple
self._dictionary[ 'colours' ][ 'darkmode' ][ CC.COLOUR_THUMB_BORDER ] = ( 145, 163, 176 ) # Cadet Grey
self._dictionary[ 'colours' ][ 'darkmode' ][ CC.COLOUR_THUMB_BORDER_SELECTED ] = ( 223, 227, 230 ) # light grey
self._dictionary[ 'colours' ][ 'darkmode' ][ CC.COLOUR_THUMB_BORDER_REMOTE ] = ( 248, 208, 204 ) # 25% Vermillion, 75% White
self._dictionary[ 'colours' ][ 'darkmode' ][ CC.COLOUR_THUMB_BORDER_REMOTE_SELECTED ] = ( 227, 66, 52 ) # Vermillion, lol
self._dictionary[ 'colours' ][ 'darkmode' ][ CC.COLOUR_THUMBGRID_BACKGROUND ] = ( 52, 52, 52 ) # 20% flat gray
self._dictionary[ 'colours' ][ 'darkmode' ][ CC.COLOUR_AUTOCOMPLETE_BACKGROUND ] = ( 83, 98, 103 ) # Gunmetal
self._dictionary[ 'colours' ][ 'darkmode' ][ CC.COLOUR_MEDIA_BACKGROUND ] = ( 52, 52, 52 ) # 20% flat gray
self._dictionary[ 'colours' ][ 'darkmode' ][ CC.COLOUR_MEDIA_TEXT ] = ( 112, 128, 144 ) # Slate Gray
self._dictionary[ 'colours' ][ 'darkmode' ][ CC.COLOUR_TAGS_BOX ] = ( 35, 38, 41 )
#
self._dictionary[ 'duplicate_action_options' ] = HydrusSerialisable.SerialisableDictionary()
duplicate_content_merge_options = ClientDuplicates.DuplicateContentMergeOptions()
duplicate_content_merge_options.SetTagServiceActions( [ ( CC.DEFAULT_LOCAL_TAG_SERVICE_KEY, HC.CONTENT_MERGE_ACTION_MOVE, HydrusTags.TagFilter() ), ( CC.DEFAULT_LOCAL_DOWNLOADER_TAG_SERVICE_KEY, HC.CONTENT_MERGE_ACTION_MOVE, HydrusTags.TagFilter() ) ] )
duplicate_content_merge_options.SetRatingServiceActions( [ ( CC.DEFAULT_FAVOURITES_RATING_SERVICE_KEY, HC.CONTENT_MERGE_ACTION_MOVE ) ] )
duplicate_content_merge_options.SetSyncArchiveAction( ClientDuplicates.SYNC_ARCHIVE_DO_BOTH_REGARDLESS )
duplicate_content_merge_options.SetSyncURLsAction( HC.CONTENT_MERGE_ACTION_COPY )
duplicate_content_merge_options.SetSyncNotesAction( HC.CONTENT_MERGE_ACTION_COPY )
from hydrus.client.importing.options import NoteImportOptions
note_import_options = NoteImportOptions.NoteImportOptions()
note_import_options.SetIsDefault( False )
note_import_options.SetGetNotes( True )
note_import_options.SetExtendExistingNoteIfPossible( True )
note_import_options.SetConflictResolution( NoteImportOptions.NOTE_IMPORT_CONFLICT_RENAME )
duplicate_content_merge_options.SetSyncNoteImportOptions( note_import_options )
self._dictionary[ 'duplicate_action_options' ][ HC.DUPLICATE_BETTER ] = duplicate_content_merge_options
duplicate_content_merge_options = ClientDuplicates.DuplicateContentMergeOptions()
duplicate_content_merge_options.SetTagServiceActions( [ ( CC.DEFAULT_LOCAL_TAG_SERVICE_KEY, HC.CONTENT_MERGE_ACTION_TWO_WAY_MERGE, HydrusTags.TagFilter() ), ( CC.DEFAULT_LOCAL_DOWNLOADER_TAG_SERVICE_KEY, HC.CONTENT_MERGE_ACTION_TWO_WAY_MERGE, HydrusTags.TagFilter() ) ] )
duplicate_content_merge_options.SetRatingServiceActions( [ ( CC.DEFAULT_FAVOURITES_RATING_SERVICE_KEY, HC.CONTENT_MERGE_ACTION_TWO_WAY_MERGE ) ] )
duplicate_content_merge_options.SetSyncArchiveAction( ClientDuplicates.SYNC_ARCHIVE_DO_BOTH_REGARDLESS )
duplicate_content_merge_options.SetSyncURLsAction( HC.CONTENT_MERGE_ACTION_TWO_WAY_MERGE )
duplicate_content_merge_options.SetSyncNotesAction( HC.CONTENT_MERGE_ACTION_TWO_WAY_MERGE )
note_import_options = NoteImportOptions.NoteImportOptions()
note_import_options.SetIsDefault( False )
note_import_options.SetGetNotes( True )
note_import_options.SetExtendExistingNoteIfPossible( True )
note_import_options.SetConflictResolution( NoteImportOptions.NOTE_IMPORT_CONFLICT_RENAME )
duplicate_content_merge_options.SetSyncNoteImportOptions( note_import_options )
self._dictionary[ 'duplicate_action_options' ][ HC.DUPLICATE_SAME_QUALITY ] = duplicate_content_merge_options
duplicate_content_merge_options = ClientDuplicates.DuplicateContentMergeOptions()
self._dictionary[ 'duplicate_action_options' ][ HC.DUPLICATE_ALTERNATE ] = duplicate_content_merge_options
#
self._dictionary[ 'integers' ] = {}
self._dictionary[ 'integers' ][ 'notebook_tab_alignment' ] = CC.DIRECTION_UP
self._dictionary[ 'integers' ][ 'video_buffer_size' ] = 96 * 1024 * 1024
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[ 'integers' ][ 'similar_files_duplicate_pairs_search_distance' ] = 0
self._dictionary[ 'integers' ][ 'default_new_page_goes' ] = CC.NEW_PAGE_GOES_FAR_RIGHT
self._dictionary[ 'integers' ][ 'max_page_name_chars' ] = 20
self._dictionary[ 'integers' ][ 'page_file_count_display' ] = CC.PAGE_FILE_COUNT_DISPLAY_ALL
self._dictionary[ 'integers' ][ 'network_timeout' ] = 10
self._dictionary[ 'integers' ][ 'connection_error_wait_time' ] = 15
self._dictionary[ 'integers' ][ 'serverside_bandwidth_wait_time' ] = 60
self._dictionary[ 'integers' ][ 'thumbnail_visibility_scroll_percent' ] = 75
self._dictionary[ 'integers' ][ 'ideal_tile_dimension' ] = 768
self._dictionary[ 'integers' ][ 'total_pages_warning' ] = 165
self._dictionary[ 'integers' ][ 'wake_delay_period' ] = 15
from hydrus.client.gui.canvas import ClientGUICanvasMedia
self._dictionary[ 'integers' ][ 'media_viewer_zoom_center' ] = ClientGUICanvasMedia.ZOOM_CENTERPOINT_MOUSE
self._dictionary[ 'integers' ][ 'last_session_save_period_minutes' ] = 5
self._dictionary[ 'integers' ][ 'shutdown_work_period' ] = 86400
self._dictionary[ 'integers' ][ 'max_network_jobs' ] = 15
self._dictionary[ 'integers' ][ 'max_network_jobs_per_domain' ] = 3
self._dictionary[ 'integers' ][ 'max_connection_attempts_allowed' ] = 5
self._dictionary[ 'integers' ][ 'max_request_attempts_allowed_get' ] = 5
from hydrus.core import HydrusImageHandling
self._dictionary[ 'integers' ][ 'thumbnail_scale_type' ] = HydrusImageHandling.THUMBNAIL_SCALE_DOWN_ONLY
self._dictionary[ 'integers' ][ 'max_simultaneous_subscriptions' ] = 1
self._dictionary[ 'integers' ][ 'gallery_page_wait_period_pages' ] = 15
self._dictionary[ 'integers' ][ 'gallery_page_wait_period_subscriptions' ] = 5
self._dictionary[ 'integers' ][ 'watcher_page_wait_period' ] = 5
self._dictionary[ 'integers' ][ 'popup_message_character_width' ] = 56
self._dictionary[ 'integers' ][ 'duplicate_filter_max_batch_size' ] = 250
self._dictionary[ 'integers' ][ 'video_thumbnail_percentage_in' ] = 35
self._dictionary[ 'integers' ][ 'global_audio_volume' ] = 70
self._dictionary[ 'integers' ][ 'media_viewer_audio_volume' ] = 70
self._dictionary[ 'integers' ][ 'preview_audio_volume' ] = 70
self._dictionary[ 'integers' ][ 'duplicate_comparison_score_higher_jpeg_quality' ] = 10
self._dictionary[ 'integers' ][ 'duplicate_comparison_score_much_higher_jpeg_quality' ] = 20
self._dictionary[ 'integers' ][ 'duplicate_comparison_score_higher_filesize' ] = 10
self._dictionary[ 'integers' ][ 'duplicate_comparison_score_much_higher_filesize' ] = 20
self._dictionary[ 'integers' ][ 'duplicate_comparison_score_higher_resolution' ] = 20
self._dictionary[ 'integers' ][ 'duplicate_comparison_score_much_higher_resolution' ] = 50
self._dictionary[ 'integers' ][ 'duplicate_comparison_score_more_tags' ] = 8
self._dictionary[ 'integers' ][ 'duplicate_comparison_score_older' ] = 4
self._dictionary[ 'integers' ][ 'duplicate_comparison_score_nicer_ratio' ] = 10
self._dictionary[ 'integers' ][ 'thumbnail_cache_size' ] = 1024 * 1024 * 32
self._dictionary[ 'integers' ][ 'image_cache_size' ] = 1024 * 1024 * 384
self._dictionary[ 'integers' ][ 'image_tile_cache_size' ] = 1024 * 1024 * 256
self._dictionary[ 'integers' ][ 'thumbnail_cache_timeout' ] = 86400
self._dictionary[ 'integers' ][ 'image_cache_timeout' ] = 600
self._dictionary[ 'integers' ][ 'image_tile_cache_timeout' ] = 300
self._dictionary[ 'integers' ][ 'image_cache_storage_limit_percentage' ] = 25
self._dictionary[ 'integers' ][ 'image_cache_prefetch_limit_percentage' ] = 10
self._dictionary[ 'integers' ][ 'media_viewer_prefetch_delay_base_ms' ] = 100
self._dictionary[ 'integers' ][ 'media_viewer_prefetch_num_previous' ] = 2
self._dictionary[ 'integers' ][ 'media_viewer_prefetch_num_next' ] = 3
self._dictionary[ 'integers' ][ 'thumbnail_border' ] = 1
self._dictionary[ 'integers' ][ 'thumbnail_margin' ] = 2
self._dictionary[ 'integers' ][ 'thumbnail_dpr_percent' ] = 100
self._dictionary[ 'integers' ][ 'file_maintenance_idle_throttle_files' ] = 1
self._dictionary[ 'integers' ][ 'file_maintenance_idle_throttle_time_delta' ] = 2
self._dictionary[ 'integers' ][ 'file_maintenance_active_throttle_files' ] = 1
self._dictionary[ 'integers' ][ 'file_maintenance_active_throttle_time_delta' ] = 20
self._dictionary[ 'integers' ][ 'subscription_network_error_delay' ] = 12 * 3600
self._dictionary[ 'integers' ][ 'subscription_other_error_delay' ] = 36 * 3600
self._dictionary[ 'integers' ][ 'downloader_network_error_delay' ] = 90 * 60
self._dictionary[ 'integers' ][ 'file_viewing_stats_menu_display' ] = CC.FILE_VIEWING_STATS_MENU_DISPLAY_MEDIA_AND_PREVIEW_IN_SUBMENU
self._dictionary[ 'integers' ][ 'number_of_gui_session_backups' ] = 10
self._dictionary[ 'integers' ][ 'animated_scanbar_height' ] = 20
self._dictionary[ 'integers' ][ 'animated_scanbar_nub_width' ] = 10
self._dictionary[ 'integers' ][ 'domain_network_infrastructure_error_number' ] = 3
self._dictionary[ 'integers' ][ 'domain_network_infrastructure_error_time_delta' ] = 600
self._dictionary[ 'integers' ][ 'ac_read_list_height_num_chars' ] = 19
self._dictionary[ 'integers' ][ 'ac_write_list_height_num_chars' ] = 11
self._dictionary[ 'integers' ][ 'system_busy_cpu_percent' ] = 50
self._dictionary[ 'integers' ][ 'human_bytes_sig_figs' ] = 3
self._dictionary[ 'integers' ][ 'ms_to_wait_between_physical_file_deletes' ] = 250
#
self._dictionary[ 'keys' ] = {}
self._dictionary[ 'keys' ][ 'default_tag_service_tab' ] = CC.DEFAULT_LOCAL_TAG_SERVICE_KEY.hex()
self._dictionary[ 'keys' ][ 'default_tag_service_search_page' ] = CC.COMBINED_TAG_SERVICE_KEY.hex()
self._dictionary[ 'keys' ][ 'default_gug_key' ] = HydrusData.GenerateKey().hex()
self._dictionary[ 'key_list' ] = {}
#
self._dictionary[ 'noneable_integers' ] = {}
self._dictionary[ 'noneable_integers' ][ 'forced_search_limit' ] = None
self._dictionary[ 'noneable_integers' ][ 'num_recent_tags' ] = 20
self._dictionary[ 'noneable_integers' ][ 'duplicate_background_switch_intensity' ] = 3
self._dictionary[ 'noneable_integers' ][ 'last_review_bandwidth_search_distance' ] = 7 * 86400
self._dictionary[ 'noneable_integers' ][ 'file_viewing_statistics_media_min_time' ] = 2
self._dictionary[ 'noneable_integers' ][ 'file_viewing_statistics_media_max_time' ] = 600
self._dictionary[ 'noneable_integers' ][ 'file_viewing_statistics_preview_min_time' ] = 5
self._dictionary[ 'noneable_integers' ][ 'file_viewing_statistics_preview_max_time' ] = 60
self._dictionary[ 'noneable_integers' ][ 'subscription_file_error_cancel_threshold' ] = 5
self._dictionary[ 'noneable_integers' ][ 'media_viewer_cursor_autohide_time_ms' ] = 700
self._dictionary[ 'noneable_integers' ][ 'idle_mode_client_api_timeout' ] = None
self._dictionary[ 'noneable_integers' ][ 'system_busy_cpu_count' ] = 1
self._dictionary[ 'noneable_integers' ][ 'animated_scanbar_hide_height' ] = 5
self._dictionary[ 'noneable_integers' ][ 'last_backup_time' ] = None
#
self._dictionary[ 'simple_downloader_formulae' ] = HydrusSerialisable.SerialisableList()
#
self._dictionary[ 'noneable_strings' ] = {}
self._dictionary[ 'noneable_strings' ][ 'favourite_file_lookup_script' ] = 'gelbooru md5'
self._dictionary[ 'noneable_strings' ][ 'suggested_tags_layout' ] = 'notebook'
self._dictionary[ 'noneable_strings' ][ 'backup_path' ] = None
self._dictionary[ 'noneable_strings' ][ 'web_browser_path' ] = None
self._dictionary[ 'noneable_strings' ][ 'last_png_export_dir' ] = None
self._dictionary[ 'noneable_strings' ][ 'media_background_bmp_path' ] = None
self._dictionary[ 'noneable_strings' ][ 'http_proxy' ] = None
self._dictionary[ 'noneable_strings' ][ 'https_proxy' ] = None
self._dictionary[ 'noneable_strings' ][ 'no_proxy' ] = '127.0.0.1'
self._dictionary[ 'noneable_strings' ][ 'qt_style_name' ] = None
self._dictionary[ 'noneable_strings' ][ 'qt_stylesheet_name' ] = None
self._dictionary[ 'noneable_strings' ][ 'last_advanced_file_deletion_reason' ] = None
self._dictionary[ 'noneable_strings' ][ 'last_advanced_file_deletion_special_action' ] = None
self._dictionary[ 'strings' ] = {}
self._dictionary[ 'strings' ][ 'app_display_name' ] = 'hydrus client'
self._dictionary[ 'strings' ][ 'namespace_connector' ] = ':'
self._dictionary[ 'strings' ][ 'export_phrase' ] = '{hash}'
self._dictionary[ 'strings' ][ 'current_colourset' ] = 'default'
self._dictionary[ 'strings' ][ 'favourite_simple_downloader_formula' ] = 'all files linked by images in page'
self._dictionary[ 'strings' ][ 'thumbnail_scroll_rate' ] = '1.0'
self._dictionary[ 'strings' ][ 'pause_character' ] = '\u23F8'
self._dictionary[ 'strings' ][ 'stop_character' ] = '\u23F9'
self._dictionary[ 'strings' ][ 'default_gug_name' ] = 'safebooru tag search'
self._dictionary[ 'strings' ][ 'has_audio_label' ] = '\U0001F50A'
self._dictionary[ 'strings' ][ 'has_duration_label' ] = ' \u23F5 '
self._dictionary[ 'strings' ][ 'discord_dnd_filename_pattern' ] = '{hash}'
self._dictionary[ 'strings' ][ 'default_suggested_tags_notebook_page' ] = 'related'
self._dictionary[ 'string_list' ] = {}
self._dictionary[ 'string_list' ][ 'default_media_viewer_custom_shortcuts' ] = []
self._dictionary[ 'string_list' ][ 'favourite_tags' ] = []
self._dictionary[ 'string_list' ][ 'advanced_file_deletion_reasons' ] = [ 'I do not like it.', 'It is bad quality.', 'It is not appropriate for this client.', 'Temporary delete--I want to bring it back later.' ]
#
from hydrus.client import ClientStrings
self._dictionary[ 'last_used_string_conversion_step' ] = ClientStrings.StringConverter( [ ( ClientStrings.STRING_CONVERSION_APPEND_TEXT, 'extra text' ) ] )
self._dictionary[ 'custom_default_predicates' ] = HydrusSerialisable.SerialisableList()
self._dictionary[ 'predicate_types_to_recent_predicates' ] = HydrusSerialisable.SerialisableDictionary()
from hydrus.client import ClientLocation
self._dictionary[ 'default_local_location_context' ] = ClientLocation.LocationContext.STATICCreateSimple( CC.LOCAL_FILE_SERVICE_KEY )
#
self._dictionary[ 'favourite_tag_filters' ] = HydrusSerialisable.SerialisableDictionary()
#
from hydrus.client.media import ClientMedia
from hydrus.client.metadata import ClientTags
default_namespace_sorts = HydrusSerialisable.SerialisableList()
default_namespace_sorts.append( ClientMedia.MediaSort( sort_type = ( 'namespaces', ( ( 'series', 'creator', 'title', 'volume', 'chapter', 'page' ), ClientTags.TAG_DISPLAY_ACTUAL ) ) ) )
default_namespace_sorts.append( ClientMedia.MediaSort( sort_type = ( 'namespaces', ( ( 'creator', 'series', 'title', 'volume', 'chapter', 'page' ), ClientTags.TAG_DISPLAY_ACTUAL ) ) ) )
self._dictionary[ 'default_namespace_sorts' ] = default_namespace_sorts
#
self._dictionary[ 'tag_summary_generators' ] = HydrusSerialisable.SerialisableDictionary()
namespace_info = []
namespace_info.append( ( 'creator', '', ', ' ) )
namespace_info.append( ( 'series', '', ', ' ) )
namespace_info.append( ( 'title', '', ', ' ) )
separator = ' - '
# the cleantags here converts to unicode, which is important!
example_tags = HydrusTags.CleanTags( [ 'creator:creator', 'series:series', 'title:title' ] )
from hydrus.client.gui import ClientGUITags
tsg = ClientGUITags.TagSummaryGenerator( namespace_info = namespace_info, separator = separator, example_tags = example_tags )
self._dictionary[ 'tag_summary_generators' ][ 'thumbnail_top' ] = tsg
namespace_info = []
namespace_info.append( ( 'volume', 'v', '-' ) )
namespace_info.append( ( 'chapter', 'c', '-' ) )
namespace_info.append( ( 'page', 'p', '-' ) )
separator = '-'
example_tags = HydrusTags.CleanTags( [ 'volume:3', 'chapter:10', 'page:330', 'page:331' ] )
tsg = ClientGUITags.TagSummaryGenerator( namespace_info = namespace_info, separator = separator, example_tags = example_tags )
self._dictionary[ 'tag_summary_generators' ][ 'thumbnail_bottom_right' ] = tsg
namespace_info = []
namespace_info.append( ( 'creator', '', ', ' ) )
namespace_info.append( ( 'series', '', ', ' ) )
namespace_info.append( ( 'title', '', ', ' ) )
namespace_info.append( ( 'volume', 'v', '-' ) )
namespace_info.append( ( 'chapter', 'c', '-' ) )
namespace_info.append( ( 'page', 'p', '-' ) )
separator = ' - '
example_tags = HydrusTags.CleanTags( [ 'creator:creator', 'series:series', 'title:title', 'volume:1', 'chapter:1', 'page:1' ] )
tsg = ClientGUITags.TagSummaryGenerator( namespace_info = namespace_info, separator = separator, example_tags = example_tags )
self._dictionary[ 'tag_summary_generators' ][ 'media_viewer_top' ] = tsg
#
self._dictionary[ 'default_file_import_options' ] = HydrusSerialisable.SerialisableDictionary()
from hydrus.client.importing.options import FileImportOptions
exclude_deleted = True
preimport_hash_check_type = FileImportOptions.DO_CHECK_AND_MATCHES_ARE_DISPOSITIVE
preimport_url_check_type = FileImportOptions.DO_CHECK
preimport_url_check_looks_for_neighbours = True
allow_decompression_bombs = True
min_size = None
max_size = None
max_gif_size = 32 * 1048576
min_resolution = None
max_resolution = None
automatic_archive = False
associate_primary_urls = True
associate_source_urls = True
from hydrus.client.importing.options import PresentationImportOptions
presentation_import_options = PresentationImportOptions.PresentationImportOptions()
presentation_import_options.SetPresentationStatus( PresentationImportOptions.PRESENTATION_STATUS_NEW_ONLY )
quiet_file_import_options = FileImportOptions.FileImportOptions()
quiet_file_import_options.SetPreImportOptions( exclude_deleted, preimport_hash_check_type, preimport_url_check_type, allow_decompression_bombs, min_size, max_size, max_gif_size, min_resolution, max_resolution )
quiet_file_import_options.SetPreImportURLCheckLooksForNeighbours( preimport_url_check_looks_for_neighbours )
quiet_file_import_options.SetPostImportOptions( automatic_archive, associate_primary_urls, associate_source_urls )
quiet_file_import_options.SetPresentationImportOptions( presentation_import_options )
self._dictionary[ 'default_file_import_options' ][ 'quiet' ] = quiet_file_import_options
loud_file_import_options = FileImportOptions.FileImportOptions()
loud_file_import_options.SetPreImportOptions( exclude_deleted, preimport_hash_check_type, preimport_url_check_type, allow_decompression_bombs, min_size, max_size, max_gif_size, min_resolution, max_resolution )
loud_file_import_options.SetPreImportURLCheckLooksForNeighbours( preimport_url_check_looks_for_neighbours )
loud_file_import_options.SetPostImportOptions( automatic_archive, associate_primary_urls, associate_source_urls )
self._dictionary[ 'default_file_import_options' ][ 'loud' ] = loud_file_import_options
#
self._dictionary[ 'frame_locations' ] = {}
# remember size, remember position, last_size, last_pos, default gravity, default position, maximised, fullscreen
self._dictionary[ 'frame_locations' ][ 'file_import_status' ] = ( True, True, None, None, ( -1, -1 ), 'topleft', False, False )
self._dictionary[ 'frame_locations' ][ 'gallery_import_log' ] = ( True, True, None, None, ( -1, -1 ), 'topleft', False, False )
self._dictionary[ 'frame_locations' ][ 'local_import_filename_tagging' ] = ( True, False, None, None, ( -1, -1 ), 'topleft', False, False )
self._dictionary[ 'frame_locations' ][ 'main_gui' ] = ( True, True, ( 800, 600 ), ( 20, 20 ), ( -1, -1 ), 'topleft', True, False )
self._dictionary[ 'frame_locations' ][ 'manage_options_dialog' ] = ( False, False, None, None, ( -1, -1 ), 'topleft', False, False )
self._dictionary[ 'frame_locations' ][ 'manage_subscriptions_dialog' ] = ( True, True, None, None, ( 1, -1 ), 'topleft', False, False )
self._dictionary[ 'frame_locations' ][ 'edit_subscription_dialog' ] = ( True, True, None, None, ( 1, -1 ), 'topleft', False, False )
self._dictionary[ 'frame_locations' ][ 'manage_tags_dialog' ] = ( False, False, None, None, ( -1, 1 ), 'topleft', False, False )
self._dictionary[ 'frame_locations' ][ 'manage_tags_frame' ] = ( False, False, None, None, ( -1, 1 ), 'topleft', False, False )
self._dictionary[ 'frame_locations' ][ 'media_viewer' ] = ( True, True, ( 640, 480 ), ( 70, 70 ), ( -1, -1 ), 'topleft', True, True )
self._dictionary[ 'frame_locations' ][ 'regular_dialog' ] = ( False, False, None, None, ( -1, -1 ), 'topleft', False, False )
self._dictionary[ 'frame_locations' ][ 'review_services' ] = ( False, True, None, None, ( -1, -1 ), 'topleft', False, False )
self._dictionary[ 'frame_locations' ][ 'deeply_nested_dialog' ] = ( False, False, None, None, ( -1, -1 ), 'topleft', False, False )
self._dictionary[ 'frame_locations' ][ 'regular_center_dialog' ] = ( False, False, None, None, ( -1, -1 ), 'center', False, False )
self._dictionary[ 'frame_locations' ][ 'file_history_chart' ] = ( True, True, ( 960, 720 ), None, ( -1, -1 ), 'topleft', False, False )
#
self._dictionary[ 'media_launch' ] = HydrusSerialisable.SerialisableDictionary() # integer keys, so got to be cleverer dict
for mime in HC.SEARCHABLE_MIMES:
self._dictionary[ 'media_launch' ][ mime ] = None
#
self._dictionary[ 'media_view' ] = self._GetDefaultMediaViewOptions()
self._dictionary[ 'media_zooms' ] = [ 0.01, 0.05, 0.1, 0.15, 0.2, 0.3, 0.5, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.5, 2.0, 3.0, 5.0, 10.0, 20.0 ]
#
self._dictionary[ 'misc' ] = HydrusSerialisable.SerialisableDictionary()
self._dictionary[ 'misc' ][ 'default_thread_watcher_options' ] = ClientDefaults.GetDefaultCheckerOptions( 'thread' )
self._dictionary[ 'misc' ][ 'default_subscription_checker_options' ] = ClientDefaults.GetDefaultCheckerOptions( 'artist subscription' )
#
self._dictionary[ 'suggested_tags' ] = HydrusSerialisable.SerialisableDictionary()
self._dictionary[ 'suggested_tags' ][ 'favourites' ] = {}
#
from hydrus.client.media import ClientMedia
self._dictionary[ 'default_sort' ] = ClientMedia.MediaSort( ( 'system', CC.SORT_FILES_BY_FILESIZE ), CC.SORT_ASC )
self._dictionary[ 'fallback_sort' ] = ClientMedia.MediaSort( ( 'system', CC.SORT_FILES_BY_IMPORT_TIME ), CC.SORT_ASC )
self._dictionary[ 'default_collect' ] = ClientMedia.MediaCollect()
#
from hydrus.client.metadata import ClientTagSorting
self._dictionary[ 'default_tag_sort' ] = ClientTagSorting.TagSort.STATICGetTextASCDefault()
#
self._dictionary[ 'default_export_files_metadata_routers' ] = HydrusSerialisable.SerialisableList()
def _InitialiseFromSerialisableInfo( self, serialisable_info ):
loaded_dictionary = HydrusSerialisable.CreateFromSerialisableTuple( serialisable_info )
for ( key, value ) in list(loaded_dictionary.items()):
if key in self._dictionary and isinstance( self._dictionary[ key ], dict ) and isinstance( value, dict ):
self._dictionary[ key ].update( value )
else:
self._dictionary[ key ] = value
def _UpdateSerialisableInfo( self, version, old_serialisable_info ):
if version == 1:
loaded_dictionary = HydrusSerialisable.CreateFromSerialisableTuple( old_serialisable_info )
if 'media_view' in loaded_dictionary:
mimes = list(loaded_dictionary[ 'media_view' ].keys())
for mime in mimes:
if mime in self._dictionary[ 'media_view' ]:
( default_media_show_action, default_preview_show_action, default_zoom_info ) = self._dictionary[ 'media_view' ][ mime ]
( media_show_action, preview_show_action, zoom_in_to_fit, exact_zooms_only, scale_up_quality, scale_down_quality ) = loaded_dictionary[ 'media_view' ][ mime ]
loaded_dictionary[ 'media_view' ][ mime ] = ( media_show_action, preview_show_action, default_zoom_info )
else:
# while devving this, I discovered some u'20' stringified keys had snuck in and hung around. let's nuke them here, in case anyone else got similar
del loaded_dictionary[ 'media_view' ][ mime ]
new_serialisable_info = loaded_dictionary.GetSerialisableTuple()
return ( 2, new_serialisable_info )
if version == 2:
# as db_dir is now moveable, let's move portable base from base_dir to db_dir
def update_portable_path( p ):
if p is None:
return p
p = os.path.normpath( p ) # collapses .. stuff and converts / to \\ for windows only
if os.path.isabs( p ):
a_p = p
else:
a_p = os.path.normpath( os.path.join( HC.BASE_DIR, p ) )
if not HC.PLATFORM_WINDOWS and not os.path.exists( a_p ):
a_p = a_p.replace( '\\', '/' )
try:
db_dir = HG.controller.GetDBDir()
p = os.path.relpath( a_p, db_dir )
if p.startswith( '..' ):
p = a_p
except:
p = a_p
if HC.PLATFORM_WINDOWS:
p = p.replace( '\\', '/' ) # store seps as /, to maintain multiplatform uniformity
return p
loaded_dictionary = HydrusSerialisable.CreateFromSerialisableTuple( old_serialisable_info )
if 'client_files_locations_ideal_weights' in loaded_dictionary:
updated_cfliw = []
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
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' ] )
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()
return ( 3, new_serialisable_info )
if version == 3:
loaded_dictionary = HydrusSerialisable.CreateFromSerialisableTuple( old_serialisable_info )
if 'media_view' in loaded_dictionary:
def convert_show_action( show_action ):
start_paused = show_action in ( CC.MEDIA_VIEWER_ACTION_SHOW_BEHIND_EMBED_PAUSED, CC.MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE_PAUSED )
start_with_embed = show_action in ( CC.MEDIA_VIEWER_ACTION_SHOW_BEHIND_EMBED, CC.MEDIA_VIEWER_ACTION_SHOW_BEHIND_EMBED_PAUSED )
if start_paused or start_with_embed:
show_action = CC.MEDIA_VIEWER_ACTION_SHOW_WITH_NATIVE
return ( show_action, start_paused, start_with_embed )
for ( mime, ( media_show_action, preview_show_action, zoom_info ) ) in list( loaded_dictionary[ 'media_view' ].items() ):
( media_show_action, media_start_paused, media_start_with_embed ) = convert_show_action( media_show_action )
( preview_show_action, preview_start_paused, preview_start_with_embed ) = convert_show_action( preview_show_action )
loaded_dictionary[ 'media_view' ][ mime ] = ( media_show_action, media_start_paused, media_start_with_embed, preview_show_action, preview_start_paused, preview_start_with_embed, zoom_info )
new_serialisable_info = loaded_dictionary.GetSerialisableTuple()
return ( 4, new_serialisable_info )
if version == 4:
serialisable_dictionary = old_serialisable_info
loaded_dictionary = HydrusSerialisable.CreateFromSerialisableTuple( serialisable_dictionary )
if 'key_list' in loaded_dictionary and 'default_neighbouring_txt_tag_service_keys' in loaded_dictionary[ 'key_list' ]:
encoded_default_neighbouring_txt_tag_service_keys = loaded_dictionary[ 'key_list' ][ 'default_neighbouring_txt_tag_service_keys' ]
default_neighbouring_txt_tag_service_keys = [ bytes.fromhex( hex_key ) for hex_key in encoded_default_neighbouring_txt_tag_service_keys ]
from hydrus.client.metadata import ClientMetadataMigration
from hydrus.client.metadata import ClientMetadataMigrationExporters
from hydrus.client.metadata import ClientMetadataMigrationImporters
importers = [ ClientMetadataMigrationImporters.SingleFileMetadataImporterMediaTags( service_key = service_key ) for service_key in default_neighbouring_txt_tag_service_keys ]
exporter = ClientMetadataMigrationExporters.SingleFileMetadataExporterTXT()
metadata_router = ClientMetadataMigration.SingleFileMetadataRouter( importers = importers, exporter = exporter )
metadata_routers = [ metadata_router ]
loaded_dictionary[ 'default_export_files_metadata_routers' ] = HydrusSerialisable.SerialisableList( metadata_routers )
del loaded_dictionary[ 'key_list' ][ 'default_neighbouring_txt_tag_service_keys' ]
new_serialisable_info = loaded_dictionary.GetSerialisableTuple()
return ( 5, new_serialisable_info )
def ClearCustomDefaultSystemPredicates( self, predicate_type = None, comparable_predicate = None ):
with self._lock:
custom_default_predicates = self._dictionary[ 'custom_default_predicates' ]
if predicate_type is not None:
new_custom_default_predicates = HydrusSerialisable.SerialisableList( [ pred for pred in custom_default_predicates if pred.GetType() != predicate_type ] )
self._dictionary[ 'custom_default_predicates' ] = new_custom_default_predicates
return
if comparable_predicate is not None:
new_custom_default_predicates = HydrusSerialisable.SerialisableList( [ pred for pred in custom_default_predicates if not pred.IsUIEditable( comparable_predicate ) ] )
self._dictionary[ 'custom_default_predicates' ] = new_custom_default_predicates
return
def FlipBoolean( self, name ):
with self._lock:
self._dictionary[ 'booleans' ][ name ] = not self._dictionary[ 'booleans' ][ name ]
def GetBoolean( self, name ):
with self._lock:
return self._dictionary[ 'booleans' ][ name ]
def GetDefaultCollect( self ):
with self._lock:
return self._dictionary[ 'default_collect' ]
def GetColour( self, colour_type, colourset = None ):
with self._lock:
if colourset is None:
colourset = self._dictionary[ 'strings' ][ 'current_colourset' ]
( r, g, b ) = self._dictionary[ 'colours' ][ colourset ][ colour_type ]
return QG.QColor( r, g, b )
def GetCustomDefaultSystemPredicates( self, predicate_type = None, comparable_predicate = None ):
with self._lock:
custom_default_predicates = self._dictionary[ 'custom_default_predicates' ]
if predicate_type is not None:
return [ pred for pred in custom_default_predicates if pred.GetType() == predicate_type ]
if comparable_predicate is not None:
return [ pred for pred in custom_default_predicates if pred.IsUIEditable( comparable_predicate ) ]
return []
def GetDefaultExportFilesMetadataRouters( self ):
with self._lock:
return list( self._dictionary[ 'default_export_files_metadata_routers' ] )
def GetDefaultFileImportOptions( self, options_type ):
with self._lock:
if options_type == FileImportOptions.IMPORT_TYPE_LOUD:
key = 'loud'
else:
key = 'quiet'
return self._dictionary[ 'default_file_import_options' ][ key ]
def GetDefaultLocalLocationContext( self ):
with self._lock:
location_context = self._dictionary[ 'default_local_location_context' ]
try:
location_context.FixMissingServices( HG.client_controller.services_manager.FilterValidServiceKeys )
if location_context.IsEmpty():
from hydrus.client import ClientLocation
location_context = ClientLocation.LocationContext.STATICCreateSimple( CC.COMBINED_LOCAL_MEDIA_SERVICE_KEY )
except:
pass
return location_context
def GetDefaultMediaViewOptions( self ):
with self._lock:
return self._GetDefaultMediaViewOptions()
def GetDefaultNamespaceSorts( self ):
with self._lock:
return list( self._dictionary[ 'default_namespace_sorts' ] )
def GetDefaultSort( self ):
with self._lock:
return self._dictionary[ 'default_sort' ]
def GetDefaultSubscriptionCheckerOptions( self ):
with self._lock:
return self._dictionary[ 'misc' ][ 'default_subscription_checker_options' ]
def GetDefaultTagSort( self ):
with self._lock:
return self._dictionary[ 'default_tag_sort' ]
def GetDefaultWatcherCheckerOptions( self ):
with self._lock:
return self._dictionary[ 'misc' ][ 'default_thread_watcher_options' ]
def GetDuplicateContentMergeOptions( self, duplicate_type ):
with self._lock:
if duplicate_type in self._dictionary[ 'duplicate_action_options' ]:
return self._dictionary[ 'duplicate_action_options' ][ duplicate_type ]
else:
return ClientDuplicates.DuplicateContentMergeOptions()
def GetFallbackSort( self ):
with self._lock:
return self._dictionary[ 'fallback_sort' ]
def GetFavouriteTagFilters( self ):
with self._lock:
return dict( self._dictionary[ 'favourite_tag_filters' ] )
def GetFrameLocation( self, frame_key ):
with self._lock:
return self._dictionary[ 'frame_locations' ][ frame_key ]
def GetFrameLocations( self ):
with self._lock:
return list(self._dictionary[ 'frame_locations' ].items())
def GetInteger( self, name ):
with self._lock:
return self._dictionary[ 'integers' ][ name ]
def GetKey( self, name ):
with self._lock:
return bytes.fromhex( self._dictionary[ 'keys' ][ name ] )
def GetKeyList( self, name ):
with self._lock:
return [ bytes.fromhex( hex_key ) for hex_key in self._dictionary[ 'key_list' ][ name ] ]
def GetMediaShowAction( self, mime ):
with self._lock:
( media_show_action, media_start_paused, media_start_with_embed, preview_show_action, preview_start_paused, preview_start_with_embed, zoom_info ) = self._GetMediaViewOptions( mime )
( possible_show_actions, can_start_paused, can_start_with_embed ) = CC.media_viewer_capabilities[ mime ]
if media_show_action not in possible_show_actions:
return ( CC.MEDIA_VIEWER_ACTION_SHOW_OPEN_EXTERNALLY_BUTTON, False, False )
return ( media_show_action, media_start_paused, media_start_with_embed )
def GetMediaViewOptions( self ):
with self._lock:
return dict( self._dictionary[ 'media_view' ] )
def GetMediaZoomOptions( self, mime ):
with self._lock:
( media_show_action, media_start_paused, media_start_with_embed, preview_show_action, preview_start_paused, preview_start_with_embed, zoom_info ) = self._GetMediaViewOptions( mime )
return zoom_info
def GetMediaZooms( self ):
with self._lock:
return list( self._dictionary[ 'media_zooms' ] )
def GetMediaZoomQuality( self, mime ):
with self._lock:
( media_show_action, media_start_paused, media_start_with_embed, preview_show_action, preview_start_paused, preview_start_with_embed, zoom_info ) = self._GetMediaViewOptions( mime )
( media_scale_up, media_scale_down, preview_scale_up, preview_scale_down, exact_zooms_only, scale_up_quality, scale_down_quality ) = zoom_info
return ( scale_up_quality, scale_down_quality )
def GetMimeLaunch( self, mime ):
with self._lock:
if mime not in self._dictionary[ 'media_launch' ]:
self._dictionary[ 'media_launch' ][ mime ] = None
return self._dictionary[ 'media_launch' ][ mime ]
def GetNoneableInteger( self, name ):
with self._lock:
return self._dictionary[ 'noneable_integers' ][ name ]
def GetNoneableString( self, name ):
with self._lock:
return self._dictionary[ 'noneable_strings' ][ name ]
def GetPreviewShowAction( self, mime ):
with self._lock:
( media_show_action, media_start_paused, media_start_with_embed, preview_show_action, preview_start_paused, preview_start_with_embed, zoom_info ) = self._GetMediaViewOptions( mime )
( possible_show_actions, can_start_paused, can_start_with_embed ) = CC.media_viewer_capabilities[ mime ]
if preview_show_action not in possible_show_actions:
return ( CC.MEDIA_VIEWER_ACTION_SHOW_OPEN_EXTERNALLY_BUTTON, False, False )
return ( preview_show_action, preview_start_paused, preview_start_with_embed )
def GetRawSerialisable( self, name ):
with self._lock:
return self._dictionary[ name ]
def GetRecentPredicates( self, predicate_types ):
with self._lock:
result = []
predicate_types_to_recent_predicates = self._dictionary[ 'predicate_types_to_recent_predicates' ]
for predicate_type in predicate_types:
if predicate_type in predicate_types_to_recent_predicates:
result.extend( predicate_types_to_recent_predicates[ predicate_type ] )
return result
def GetSimpleDownloaderFormulae( self ):
with self._lock:
return self._dictionary[ 'simple_downloader_formulae' ]
def GetString( self, name ):
with self._lock:
return self._dictionary[ 'strings' ][ name ]
def GetStringList( self, name ):
with self._lock:
return self._dictionary[ 'string_list' ][ name ]
def GetSuggestedTagsFavourites( self, service_key ):
with self._lock:
service_key_hex = service_key.hex()
stf = self._dictionary[ 'suggested_tags' ][ 'favourites' ]
if service_key_hex in stf:
return set( stf[ service_key_hex ] )
else:
return set()
def GetTagSummaryGenerator( self, name ):
with self._lock:
return self._dictionary[ 'tag_summary_generators' ][ name ]
def InvertBoolean( self, name ):
with self._lock:
self._dictionary[ 'booleans' ][ name ] = not self._dictionary[ 'booleans' ][ name ]
def PushRecentPredicates( self, predicates ):
with self._lock:
predicate_types_to_recent_predicates = self._dictionary[ 'predicate_types_to_recent_predicates' ]
for predicate in predicates:
predicate_type = predicate.GetType()
if predicate_type not in predicate_types_to_recent_predicates:
predicate_types_to_recent_predicates[ predicate_type ] = HydrusSerialisable.SerialisableList()
recent_predicates = predicate_types_to_recent_predicates[ predicate_type ]
if predicate in recent_predicates:
recent_predicates.remove( predicate )
recent_predicates.insert( 0, predicate )
while len( recent_predicates ) > 5:
recent_predicates.pop( 5 )
def RemoveRecentPredicate( self, predicate ):
with self._lock:
predicate_types_to_recent_predicates = self._dictionary[ 'predicate_types_to_recent_predicates' ]
for recent_predicates in predicate_types_to_recent_predicates.values():
if predicate in recent_predicates:
recent_predicates.remove( predicate )
return
def SetBoolean( self, name, value ):
with self._lock:
self._dictionary[ 'booleans' ][ name ] = value
def SetDefaultCollect( self, media_collect ):
with self._lock:
self._dictionary[ 'default_collect' ] = media_collect
def SetColour( self, colour_type, colourset, colour ):
with self._lock:
if isinstance( colour, QG.QColor ):
c = colour
( r, g, b ) = ( c.red(), c.green(), c.blue() )
else:
( r, g, b ) = colour
self._dictionary[ 'colours' ][ colourset ][ colour_type ] = ( r, g, b )
def SetCustomDefaultSystemPredicates( self, predicate_type = None, predicates = None, comparable_predicates = None ):
with self._lock:
custom_default_predicates = self._dictionary[ 'custom_default_predicates' ]
if predicate_type is not None and predicates is not None:
new_custom_default_predicates = HydrusSerialisable.SerialisableList( [ pred for pred in custom_default_predicates if pred.GetType() != predicate_type ] )
new_custom_default_predicates.extend( predicates )
self._dictionary[ 'custom_default_predicates' ] = new_custom_default_predicates
return
if comparable_predicates is not None:
new_custom_default_predicates = HydrusSerialisable.SerialisableList()
for pred in custom_default_predicates:
if True not in ( pred.IsUIEditable( comparable_predicate ) for comparable_predicate in comparable_predicates ):
new_custom_default_predicates.append( pred )
new_custom_default_predicates.extend( comparable_predicates )
self._dictionary[ 'custom_default_predicates' ] = new_custom_default_predicates
return
def SetDefaultExportFilesMetadataRouters( self, metadata_routers ):
with self._lock:
self._dictionary[ 'default_export_files_metadata_routers' ] = HydrusSerialisable.SerialisableList( metadata_routers )
def SetDefaultFileImportOptions( self, options_type, file_import_options ):
with self._lock:
if options_type == FileImportOptions.IMPORT_TYPE_LOUD:
key = 'loud'
else:
key = 'quiet'
self._dictionary[ 'default_file_import_options' ][ key ] = file_import_options
def SetDefaultLocalLocationContext( self, location_context ):
with self._lock:
self._dictionary[ 'default_local_location_context' ] = location_context
def SetDefaultNamespaceSorts( self, namespace_sorts ):
with self._lock:
default_namespace_sorts = HydrusSerialisable.SerialisableList()
for namespace_sort in namespace_sorts:
default_namespace_sorts.append( namespace_sort )
self._dictionary[ 'default_namespace_sorts' ] = default_namespace_sorts
def SetDefaultTagSort( self, tag_sort ):
with self._lock:
self._dictionary[ 'default_tag_sort' ] = tag_sort
def SetDefaultSort( self, media_sort ):
with self._lock:
self._dictionary[ 'default_sort' ] = media_sort
def SetDefaultSubscriptionCheckerOptions( self, checker_options ):
with self._lock:
self._dictionary[ 'misc' ][ 'default_subscription_checker_options' ] = checker_options
def SetDefaultWatcherCheckerOptions( self, checker_options ):
with self._lock:
self._dictionary[ 'misc' ][ 'default_thread_watcher_options' ] = checker_options
def SetDuplicateContentMergeOptions( self, duplicate_type, duplicate_content_merge_options ):
with self._lock:
self._dictionary[ 'duplicate_action_options' ][ duplicate_type ] = duplicate_content_merge_options
def SetFallbackSort( self, media_sort ):
with self._lock:
self._dictionary[ 'fallback_sort' ] = media_sort
def SetFavouriteTagFilters( self, names_to_tag_filters ):
with self._lock:
self._dictionary[ 'favourite_tag_filters' ] = HydrusSerialisable.SerialisableDictionary( names_to_tag_filters )
def SetFrameLocation( self, frame_key, remember_size, remember_position, last_size, last_position, default_gravity, default_position, maximised, fullscreen ):
with self._lock:
self._dictionary[ 'frame_locations' ][ frame_key ] = ( remember_size, remember_position, last_size, last_position, default_gravity, default_position, maximised, fullscreen )
def SetInteger( self, name, value ):
with self._lock:
self._dictionary[ 'integers' ][ name ] = value
def SetKey( self, name, value ):
with self._lock:
self._dictionary[ 'keys' ][ name ] = value.hex()
def SetKeyList( self, name, value ):
with self._lock:
self._dictionary[ 'key_list' ][ name ] = [ key.hex() for key in value ]
def SetMediaViewOptions( self, mimes_to_media_view_options ):
with self._lock:
self._dictionary[ 'media_view' ] = HydrusSerialisable.SerialisableDictionary( mimes_to_media_view_options )
def SetMediaZooms( self, zooms ):
with self._lock:
self._dictionary[ 'media_zooms' ] = zooms
def SetMimeLaunch( self, mime, launch_path ):
with self._lock:
self._dictionary[ 'media_launch' ][ mime ] = launch_path
def SetNoneableInteger( self, name, value ):
with self._lock:
self._dictionary[ 'noneable_integers' ][ name ] = value
def SetNoneableString( self, name, value ):
with self._lock:
self._dictionary[ 'noneable_strings' ][ name ] = value
def SetRawSerialisable( self, name, value ):
with self._lock:
self._dictionary[ name ] = value
def SetSimpleDownloaderFormulae( self, simple_downloader_formulae ):
with self._lock:
self._dictionary[ 'simple_downloader_formulae' ] = HydrusSerialisable.SerialisableList( simple_downloader_formulae )
def SetString( self, name, value ):
with self._lock:
it_changed = False
if value is not None and value != '':
if self._dictionary[ 'strings' ][ name ] != value:
self._dictionary[ 'strings' ][ name ] = value
it_changed = True
def SetStringList( self, name, value ):
with self._lock:
self._dictionary[ 'string_list' ][ name ] = list( value )
def SetSuggestedTagsFavourites( self, service_key, tags ):
with self._lock:
service_key_hex = service_key.hex()
self._dictionary[ 'suggested_tags' ][ 'favourites' ][ service_key_hex ] = list( tags )
def SetTagSummaryGenerator( self, name, tag_summary_generator ):
with self._lock:
self._dictionary[ 'tag_summary_generators' ][ name ] = tag_summary_generator
HydrusSerialisable.SERIALISABLE_TYPES_TO_OBJECT_TYPES[ HydrusSerialisable.SERIALISABLE_TYPE_CLIENT_OPTIONS ] = ClientOptions