def EventClear( self ): from hydrus.client.gui import ClientGUIDialogsQuick result = ClientGUIDialogsQuick.GetYesNo( self, 'Clear recent tags?' ) if result == QW.QDialog.Accepted: HG.client_controller.Write( 'push_recent_tags', self._service_key, None ) self._last_fetched_tags = [] self._UpdateTagDisplay()
def UserIsOKToOK(self): if self._delete_from_client_after_export.isChecked(): message = 'You have set this export folder to delete the files from the client after export! Are you absolutely sure this is what you want?' result = ClientGUIDialogsQuick.GetYesNo(self, message) if result != QW.QDialog.Accepted: return False return True
def _DeleteSelected(self): file_seeds_to_delete = self._list_ctrl.GetData(only_selected=True) if len(file_seeds_to_delete) > 0: message = 'Are you sure you want to delete the {} selected entries?'.format( HydrusData.ToHumanInt(len(file_seeds_to_delete))) result = ClientGUIDialogsQuick.GetYesNo(self, message) if result == QW.QDialog.Accepted: self._file_seed_cache.RemoveFileSeeds(file_seeds_to_delete)
def ImportFromDragDrop(self, paths): from hydrus.client.gui import ClientGUIDialogsQuick message = 'Try to import the ' + HydrusData.ToHumanInt(len( paths)) + ' dropped files to this list? I am expecting png files.' result = ClientGUIDialogsQuick.GetYesNo(self, message) if result == QW.QDialog.Accepted: self._ImportPngs(paths) self._listctrl.Sort()
def _DeleteSelected(self): gallery_seeds_to_delete = self._list_ctrl.GetData(only_selected=True) if len(gallery_seeds_to_delete) > 0: message = 'Are you sure you want to delete the {} selected entries? This is only useful if you have a really really huge list.'.format( HydrusData.ToHumanInt(len(gallery_seeds_to_delete))) result = ClientGUIDialogsQuick.GetYesNo(self, message) if result == QW.QDialog.Accepted: self._gallery_seed_log.RemoveGallerySeeds( gallery_seeds_to_delete)
def _ClearGallerySeeds(self, statuses_to_remove): st_text = '/'.join( (CC.status_string_lookup[status] for status in statuses_to_remove)) message = 'Are you sure you want to delete all the {} {} log entries? This is useful for cleaning up and de-laggifying a very large list, but be careful you aren\'t removing something you would want to revisit.'.format( st_text, self._gallery_type_string) result = ClientGUIDialogsQuick.GetYesNo(self, message) if result == QW.QDialog.Accepted: gallery_seed_log = self._gallery_seed_log_get_callable() gallery_seed_log.RemoveGallerySeedsByStatus(statuses_to_remove)
def _SetSelected(self, status_to_set): file_seeds = self._list_ctrl.GetData(only_selected=True) if status_to_set == CC.STATUS_UNKNOWN: deleted_and_clearable_file_seeds = [ file_seed for file_seed in file_seeds if file_seed.IsDeleted() and file_seed.HasHash() ] if len(deleted_and_clearable_file_seeds) > 0: message = 'One or more of these files did not import due to being previously deleted. They will likely fail again unless you erase those deletion records. Would you like to do this now?' result = ClientGUIDialogsQuick.GetYesNo(self, message) if result == QW.QDialog.DialogCode.Accepted: deletee_hashes = { file_seed.GetHash() for file_seed in deleted_and_clearable_file_seeds } content_update_erase_record = HydrusData.ContentUpdate( HC.CONTENT_TYPE_FILES, HC.CONTENT_UPDATE_ADVANCED, ('delete_deleted', deletee_hashes)) content_update_undelete_from_trash = HydrusData.ContentUpdate( HC.CONTENT_TYPE_FILES, HC.CONTENT_UPDATE_UNDELETE, deletee_hashes) service_keys_to_content_updates = { CC.COMBINED_LOCAL_FILE_SERVICE_KEY: [ content_update_erase_record, content_update_undelete_from_trash ] } HG.client_controller.WriteSynchronous( 'content_updates', service_keys_to_content_updates) for file_seed in file_seeds: file_seed.SetStatus(status_to_set) self._file_seed_cache.NotifyFileSeedsUpdated(file_seeds)
def ImportFromDragDrop(self, paths): from hydrus.client.gui import ClientGUIDialogsQuick message = 'Try to import the {} dropped files to this list? I am expecting json or png files.'.format( HydrusData.ToHumanInt(len(paths))) result = ClientGUIDialogsQuick.GetYesNo(self, message) if result == QW.QDialog.Accepted: (jsons, pngs) = HydrusData.PartitionIteratorIntoLists( lambda path: path.endswith('.png'), paths) self._ImportPNGs(pngs) self._ImportJSONs(jsons) self._listctrl.Sort()
def _OpenSelectedGalleryURLs(self): gallery_seeds = self._list_ctrl.GetData(only_selected=True) if len(gallery_seeds) > 0: if len(gallery_seeds) > 10: message = 'You have many objects selected--are you sure you want to open them all?' result = ClientGUIDialogsQuick.GetYesNo(self, message) if result != QW.QDialog.Accepted: return for gallery_seed in gallery_seeds: ClientPaths.LaunchURLInWebBrowser(gallery_seed.url)
def RemovePotentials(win, hashes): if len(hashes) == 1: message = 'Are you sure you want to remove all of this file\'s potentials?' message += os.linesep * 2 message += 'This will mean it (or any of its duplicates) will not appear in the duplicate filter unless new potentials are found with new files. Use this command if the file has accidentally received many false positive potential relationships.' else: message = 'Are you sure you want to remove all of these {} files\' potentials?'.format( HydrusData.ToHumanInt(len(hashes))) message += os.linesep * 2 message += 'This will mean they (or any of their duplicates) will not appear in the duplicate filter unless new potentials are found with new files. Use this command if the files have accidentally received many false positive potential relationships.' result = ClientGUIDialogsQuick.GetYesNo(win, message) if result == QW.QDialog.Accepted: HG.client_controller.Write('remove_potential_pairs', hashes)
def ResetPotentialSearch(win, hashes): if len(hashes) == 1: message = 'Are you sure you want to search this file for potential duplicates again?' message += os.linesep * 2 message += 'This will not remove any existing potential pairs, and will typically not find any new relationships unless an error has occured.' else: message = 'Are you sure you want to search these {} files for potential duplicates again?'.format( HydrusData.ToHumanInt(len(hashes))) message += os.linesep * 2 message += 'This will not remove any existing potential pairs, and will typically not find any new relationships unless an error has occured.' result = ClientGUIDialogsQuick.GetYesNo(win, message) if result == QW.QDialog.Accepted: HG.client_controller.Write('reset_potential_search_status', hashes)
def _Remove(self): text = 'Remove these port mappings?' text += os.linesep * 2 text += 'If a mapping does not disappear after a remove, it may be hard-added in the router\'s settings interface. In this case, you will have to go there to fix it.' result = ClientGUIDialogsQuick.GetYesNo(self, text, yes_label='do it', no_label='forget it') if result != QW.QDialog.Accepted: return selected_mappings = self._mappings_list.GetData(only_selected=True) def work_callable(): for selected_mapping in selected_mappings: (description, internal_ip, internal_port, external_port, protocol, duration) = selected_mapping HydrusNATPunch.RemoveUPnPMapping(external_port, protocol) return True def publish_callable(result): self._mappings_listctrl_panel.setEnabled(True) self._RefreshMappings() self._mappings_listctrl_panel.setEnabled(False) async_job = ClientGUIAsync.AsyncQtJob(self, work_callable, publish_callable) async_job.start()
def UserIsOKToCancel(self): if self._job_key.IsDone(): self._ReleaseMessage() elif self._job_key.IsCancellable(): text = 'Cancel/stop job?' self._yesno_open = True try: result = ClientGUIDialogsQuick.GetYesNo(self, text) finally: self._yesno_open = False if result == QW.QDialog.Accepted: self._job_key.Cancel() self._ReleaseMessage() else: return False else: QW.QMessageBox.warning( self, 'Warning', 'Unfortunately, this job cannot be cancelled. If it really is taking too long, please kill the client through task manager.' ) return False return True
def _OpenSelectedFileSeedData( self ): file_seeds = self._list_ctrl.GetData( only_selected = True ) if len( file_seeds ) > 0: if len( file_seeds ) > 10: message = 'You have many objects selected--are you sure you want to open them all?' result = ClientGUIDialogsQuick.GetYesNo( self, message ) if result != QW.QDialog.Accepted: return if file_seeds[0].file_seed_data.startswith( 'http' ): for file_seed in file_seeds: ClientPaths.LaunchURLInWebBrowser( file_seed.file_seed_data ) else: try: for file_seed in file_seeds: HydrusPaths.OpenFileLocation( file_seed.file_seed_data ) except Exception as e: QW.QMessageBox.critical( self, 'Error', str(e) )
def DissolveDuplicateGroup(win, hashes): if len(hashes) == 1: message = 'Are you sure you want to dissolve this file\'s duplicate group?' message += os.linesep * 2 message += 'This will split the duplicates group back into individual files and remove any alternate relations they have. They will be queued back up in the duplicate filter for reprocessing.' message += os.linesep * 2 message += 'This could be a big change that throws away many previous decisions and cannot be undone. If you can achieve your result just by removing one or two members, do that instead.' else: message = 'Are you sure you want to dissolve these {} files\' duplicate groups?'.format( HydrusData.ToHumanInt(len(hashes))) message += os.linesep * 2 message += 'This will split all the files\' duplicates groups back into individual files and remove any alternate relations they have. They will all be queued back up in the duplicate filter for reprocessing.' message += os.linesep * 2 message += 'This could be a huge change that throws away many previous decisions and cannot be undone. If you can achieve your result just by removing some members, do that instead.' result = ClientGUIDialogsQuick.GetYesNo(win, message) if result == QW.QDialog.Accepted: HG.client_controller.Write('dissolve_duplicates_group', hashes)
def RemoveFromAlternateGroup(win, hashes): if len(hashes) == 1: message = 'Are you sure you want to remove this file from its alternates group?' message += os.linesep * 2 message += 'Alternate relationships are stored between duplicate groups, so this will pull any duplicates of your file with it.' message += os.linesep * 2 message += 'The removed file (and any duplicates) will be queued up for another potential duplicates search, so you will likely see at least one again in the duplicate filter.' else: message = 'Are you sure you want to remove these {} files from their alternates groups?'.format( HydrusData.ToHumanInt(len(hashes))) message += os.linesep * 2 message += 'Alternate relationships are stored between duplicate groups, so this will pull any duplicates of these files with them.' message += os.linesep * 2 message += 'The removed files (and any duplicates) will be queued up for another potential duplicates search, so you will likely see some again in the duplicate filter.' result = ClientGUIDialogsQuick.GetYesNo(win, message) if result == QW.QDialog.Accepted: HG.client_controller.Write('remove_alternates_member', hashes)
def ClearFalsePositives(win, hashes): if len(hashes) == 1: message = 'Are you sure you want to clear this file of its false-positive relations?' message += os.linesep * 2 message += 'False-positive relations are recorded between alternate groups, so this change will also affect any files this file is alternate to.' message += os.linesep * 2 message += 'All affected files will be queued up for another potential duplicates search, so you will likely see at least one of them again in the duplicate filter.' else: message = 'Are you sure you want to clear these {} files of their false-positive relations?'.format( HydrusData.ToHumanInt(len(hashes))) message += os.linesep * 2 message += 'False-positive relations are recorded between alternate groups, so this change will also affect all alternate files to your selection.' message += os.linesep * 2 message += 'All affected files will be queued up for another potential duplicates search, so you will likely see some of them again in the duplicate filter.' result = ClientGUIDialogsQuick.GetYesNo(win, message) if result == QW.QDialog.Accepted: HG.client_controller.Write('clear_false_positive_relations', hashes)
def DissolveAlternateGroup(win, hashes): if len(hashes) == 1: message = 'Are you sure you want to dissolve this file\'s entire alternates group?' message += os.linesep * 2 message += 'This will completely remove all duplicate, alternate, and false-positive relations for all files in the group and set them to come up again in the duplicate filter.' message += os.linesep * 2 message += 'This is a potentially big change that throws away many previous decisions and cannot be undone. If you can achieve your result just by removing some alternate members, do that instead.' else: message = 'Are you sure you want to dissolve these {} files\' entire alternates groups?'.format( HydrusData.ToHumanInt(len(hashes))) message += os.linesep * 2 message += 'This will completely remove all duplicate, alternate, and false-positive relations for all alternate groups of all files selected and set them to come up again in the duplicate filter.' message += os.linesep * 2 message += 'This is a potentially huge change that throws away many previous decisions and cannot be undone. If you can achieve your result just by removing some alternate members, do that instead.' result = ClientGUIDialogsQuick.GetYesNo(win, message) if result == QW.QDialog.Accepted: HG.client_controller.Write('dissolve_alternates_group', hashes)
def RemoveFromDuplicateGroup(win, hashes): if len(hashes) == 1: message = 'Are you sure you want to remove this file from its duplicate group?' message += os.linesep * 2 message += 'The remaining group will be otherwise unaffected and will keep its alternate relationships.' message += os.linesep * 2 message += 'The removed file will be queued up for another potential duplicates search, so you will likely see it again in the duplicate filter.' else: message = 'Are you sure you want to remove these {} files from their duplicate groups?'.format( HydrusData.ToHumanInt(len(hashes))) message += os.linesep * 2 message += 'The remaining groups will be otherwise unaffected and keep their alternate relationships.' message += os.linesep * 2 message += 'The removed files will be queued up for another potential duplicates search, so you will likely see them again in the duplicate filter.' result = ClientGUIDialogsQuick.GetYesNo(win, message) if result == QW.QDialog.Accepted: HG.client_controller.Write('remove_duplicates_member', hashes)
def _ImportURLs(self, urls): gallery_seed_log = self._gallery_seed_log_get_callable() urls = HydrusData.DedupeList(urls) filtered_urls = [ url for url in urls if not gallery_seed_log.HasGalleryURL(url) ] urls_to_add = urls if len(filtered_urls) < len(urls): num_urls = len(urls) num_removed = num_urls - len(filtered_urls) message = 'Of the ' + HydrusData.ToHumanInt( num_urls ) + ' URLs you mean to add, ' + HydrusData.ToHumanInt( num_removed ) + ' are already in the search log. Would you like to only add new URLs or add everything (which will force a re-check of the duplicates)?' (result, was_cancelled) = ClientGUIDialogsQuick.GetYesNo( self, message, yes_label='only add new urls', no_label='add all urls, even duplicates', check_for_cancelled=True) if was_cancelled: return if result == QW.QDialog.Accepted: urls_to_add = filtered_urls elif result == QW.QDialog.Rejected: return can_generate_more_pages = False if self._can_generate_more_pages: message = 'Would you like these urls to only check for new files, or would you like them to also generate subsequent gallery pages, like a regular search would?' (result, was_cancelled) = ClientGUIDialogsQuick.GetYesNo( self, message, yes_label='just check what I am adding', no_label='start a potential new search for every url added', check_for_cancelled=True) if was_cancelled: return can_generate_more_pages = result == QW.QDialog.Rejected gallery_seeds = [ ClientImportGallerySeeds.GallerySeed( url, can_generate_more_pages=can_generate_more_pages) for url in urls_to_add ] gallery_seed_log.AddGallerySeeds(gallery_seeds)
def _Delete(self): result = ClientGUIDialogsQuick.GetYesNo(self, 'Remove all selected?') if result == QW.QDialog.Accepted: account_types_about_to_delete = self._account_types_listctrl.GetData( only_selected=True) if True in (at.IsNullAccount() for at in account_types_about_to_delete): QW.QMessageBox.critical( self, 'Error', 'You cannot delete the null account type!') return all_real_account_types = set([ at for at in self._account_types_listctrl.GetData() if not at.IsNullAccount() ]) account_types_can_move_to = all_real_account_types.difference( account_types_about_to_delete) if len(account_types_can_move_to) == 0: QW.QMessageBox.critical( self, 'Error', 'You cannot delete every account type!') return for deletee_account_type in account_types_about_to_delete: if len(account_types_can_move_to) > 1: deletee_title = deletee_account_type.GetTitle() choice_tuples = [ (account_type.GetTitle(), account_type) for account_type in account_types_can_move_to ] try: new_account_type = ClientGUIDialogsQuick.SelectFromList( self, 'what should deleted ' + deletee_title + ' accounts become?', choice_tuples) except HydrusExceptions.CancelledException: return else: (new_account_type, ) = account_types_can_move_to deletee_account_type_key = deletee_account_type.GetAccountTypeKey( ) new_account_type_key = new_account_type.GetAccountTypeKey() self._deletee_account_type_keys_to_new_account_type_keys[ deletee_account_type_key] = new_account_type_key self._account_types_listctrl.DeleteSelected()
def MoveOrDuplicateLocalFiles( win: QW.QWidget, dest_service_key: bytes, action: int, media: typing.Collection[ ClientMedia.MediaSingleton ], source_service_key: typing.Optional[ bytes ] = None ): dest_service_name = HG.client_controller.services_manager.GetName( dest_service_key ) applicable_media = [ m for m in media if m.GetLocationsManager().IsLocal() and dest_service_key not in m.GetLocationsManager().GetCurrent() and m.GetMime() not in HC.HYDRUS_UPDATE_FILES ] if len( applicable_media ) == 0: return ( local_duplicable_to_file_service_keys, local_moveable_from_and_to_file_service_keys ) = GetLocalFileActionServiceKeys( media ) do_yes_no = True yes_no_text = 'Add {} files to {}?'.format( HydrusData.ToHumanInt( len( applicable_media ) ), dest_service_name ) if action == HC.CONTENT_UPDATE_MOVE: local_moveable_from_and_to_file_service_keys = { pair for pair in local_moveable_from_and_to_file_service_keys if pair[1] == dest_service_key } potential_source_service_keys = { pair[0] for pair in local_moveable_from_and_to_file_service_keys } potential_source_service_keys_to_applicable_media = collections.defaultdict( list ) for m in applicable_media: current = m.GetLocationsManager().GetCurrent() for potential_source_service_key in potential_source_service_keys: if potential_source_service_key in current: potential_source_service_keys_to_applicable_media[ potential_source_service_key ].append( m ) if source_service_key is None: if len( potential_source_service_keys ) == 0: return elif len( potential_source_service_keys ) == 1: ( source_service_key, ) = potential_source_service_keys else: do_yes_no = False num_applicable_media = len( applicable_media ) choice_tuples = [] for potential_source_service_key in potential_source_service_keys: potential_source_service_name = HG.client_controller.services_manager.GetName( potential_source_service_key ) text = 'move {} in "{}" to "{}"'.format( len( potential_source_service_keys_to_applicable_media[ potential_source_service_key ] ), potential_source_service_name, dest_service_name ) description = 'Move from {} to {}.'.format( potential_source_service_name, dest_service_name ) choice_tuples.append( ( text, potential_source_service_key, description ) ) choice_tuples.sort() try: source_service_key = ClientGUIDialogsQuick.SelectFromListButtons( win, 'select source service', choice_tuples, message = 'Select where we are moving from. Note this may not cover all files.' ) except HydrusExceptions.CancelledException: return source_service_name = HG.client_controller.services_manager.GetName( source_service_key ) applicable_media = potential_source_service_keys_to_applicable_media[ source_service_key ] yes_no_text = 'Move {} files from {} to {}?'.format( HydrusData.ToHumanInt( len( applicable_media ) ), source_service_name, dest_service_name ) if len( applicable_media ) == 0: return if do_yes_no: result = ClientGUIDialogsQuick.GetYesNo( win, yes_no_text ) if result != QW.QDialog.Accepted: return def work_callable(): job_key = ClientThreading.JobKey( cancellable = True ) title = 'moving files' if action == HC.CONTENT_UPDATE_MOVE else 'adding files' job_key.SetStatusTitle( title ) BLOCK_SIZE = 64 if len( applicable_media ) > BLOCK_SIZE: HG.client_controller.pub( 'message', job_key ) pauser = HydrusData.BigJobPauser() num_to_do = len( applicable_media ) now = HydrusData.GetNow() for ( i, block_of_media ) in enumerate( HydrusData.SplitListIntoChunks( applicable_media, BLOCK_SIZE ) ): if job_key.IsCancelled(): break job_key.SetVariable( 'popup_text_1', HydrusData.ConvertValueRangeToPrettyString( i * BLOCK_SIZE, num_to_do ) ) job_key.SetVariable( 'popup_gauge_1', ( i * BLOCK_SIZE, num_to_do ) ) content_updates = [] undelete_hashes = set() for m in block_of_media: if dest_service_key in m.GetLocationsManager().GetDeleted(): undelete_hashes.add( m.GetHash() ) else: content_updates.append( HydrusData.ContentUpdate( HC.CONTENT_TYPE_FILES, HC.CONTENT_UPDATE_ADD, ( m.GetMediaResult().GetFileInfoManager(), now ) ) ) if len( undelete_hashes ) > 0: content_updates.append( HydrusData.ContentUpdate( HC.CONTENT_TYPE_FILES, HC.CONTENT_UPDATE_UNDELETE, undelete_hashes ) ) HG.client_controller.WriteSynchronous( 'content_updates', { dest_service_key : content_updates } ) if action == HC.CONTENT_UPDATE_MOVE: block_of_hashes = [ m.GetHash() for m in block_of_media ] content_updates = [ HydrusData.ContentUpdate( HC.CONTENT_TYPE_FILES, HC.CONTENT_UPDATE_DELETE, block_of_hashes, reason = 'Moved to {}'.format( dest_service_name ) ) ] HG.client_controller.WriteSynchronous( 'content_updates', { source_service_key : content_updates } ) pauser.Pause() job_key.Delete() def publish_callable( result ): pass job = ClientGUIAsync.AsyncQtJob( win, work_callable, publish_callable ) job.start()
def OpenURLs(urls): urls = sorted(urls) if len(urls) > 1: message = 'Open the {} URLs in your web browser?'.format(len(urls)) if len(urls) > 10: message += ' This will take some time.' tlw = HG.client_controller.GetMainTLW() result = ClientGUIDialogsQuick.GetYesNo(tlw, message) if result != QW.QDialog.Accepted: return def do_it(urls): job_key = None num_urls = len(urls) if num_urls > 5: job_key = ClientThreading.JobKey(pausable=True, cancellable=True) job_key.SetVariable('popup_title', 'Opening URLs') HG.client_controller.pub('message', job_key) try: for (i, url) in enumerate(urls): if job_key is not None: (i_paused, should_quit) = job_key.WaitIfNeeded() if should_quit: return job_key.SetVariable( 'popup_text_1', HydrusData.ConvertValueRangeToPrettyString( i + 1, num_urls)) job_key.SetVariable('popup_gauge_1', (i + 1, num_urls)) ClientPaths.LaunchURLInWebBrowser(url) time.sleep(1) finally: if job_key is not None: job_key.Finish() job_key.Delete(1) HG.client_controller.CallToThread(do_it, urls)
def UndeleteMedia( win, media ): media_deleted_service_keys = HydrusData.MassUnion( ( m.GetLocationsManager().GetDeleted() for m in media ) ) local_file_services = HG.client_controller.services_manager.GetServices( ( HC.LOCAL_FILE_DOMAIN, ) ) undeletable_services = [ local_file_service for local_file_service in local_file_services if local_file_service.GetServiceKey() in media_deleted_service_keys ] if len( undeletable_services ) > 0: do_it = False if len( undeletable_services ) > 1: choice_tuples = [] for ( i, service ) in enumerate( undeletable_services ): choice_tuples.append( ( service.GetName(), service, 'Undelete back to {}.'.format( service.GetName() ) ) ) if len( choice_tuples ) > 1: service = HG.client_controller.services_manager.GetService( CC.COMBINED_LOCAL_MEDIA_SERVICE_KEY ) choice_tuples.append( ( 'all the above', service, 'Undelete back to all services the files have been deleted from.' ) ) try: undelete_service = ClientGUIDialogsQuick.SelectFromListButtons( win, 'Undelete for?', choice_tuples ) do_it = True except HydrusExceptions.CancelledException: return else: ( undelete_service, ) = undeletable_services if HC.options[ 'confirm_trash' ]: result = ClientGUIDialogsQuick.GetYesNo( win, 'Undelete this file back to {}?'.format( undelete_service.GetName() ) ) if result == QW.QDialog.Accepted: do_it = True else: do_it = True if do_it: for chunk_of_media in HydrusData.SplitIteratorIntoChunks( media, 64 ): service_keys_to_content_updates = collections.defaultdict( list ) service_key = undelete_service.GetServiceKey() undeletee_hashes = [ m.GetHash() for m in chunk_of_media if service_key in m.GetLocationsManager().GetDeleted() ] service_keys_to_content_updates[ service_key ] = [ HydrusData.ContentUpdate( HC.CONTENT_TYPE_FILES, HC.CONTENT_UPDATE_UNDELETE, undeletee_hashes ) ] HG.client_controller.Write( 'content_updates', service_keys_to_content_updates )
def _DoExport(self, quit_afterwards=False): delete_afterwards = self._delete_files_after_export.isChecked() export_symlinks = self._export_symlinks.isChecked( ) and not delete_afterwards if quit_afterwards: message = 'Export as shown?' if delete_afterwards: message += os.linesep * 2 message += 'THE FILES WILL BE DELETED FROM THE CLIENT AFTERWARDS' result = ClientGUIDialogsQuick.GetYesNo(self, message) if result != QW.QDialog.Accepted: self.parentWidget().close() return elif delete_afterwards: message = 'THE FILES WILL BE DELETED FROM THE CLIENT AFTERWARDS' result = ClientGUIDialogsQuick.GetYesNo(self, message) if result != QW.QDialog.Accepted: return self._RefreshPaths() export_tag_txts = self._export_tag_txts.isChecked() if self._export_tag_txts.isChecked(): neighbouring_txt_tag_service_keys = self._neighbouring_txt_tag_service_keys else: neighbouring_txt_tag_service_keys = [] directory = self._directory_picker.GetPath() HydrusPaths.MakeSureDirectoryExists(directory) pattern = self._pattern.text() HG.client_controller.new_options.SetString('export_phrase', pattern) try: terms = ClientExporting.ParseExportPhrase(pattern) except Exception as e: QW.QMessageBox.critical(self, 'Error', str(e)) return client_files_manager = HG.client_controller.client_files_manager self._export.setEnabled(False) to_do = self._paths.GetData() to_do = [(ordering_index, media, self._GetPath(media)) for (ordering_index, media) in to_do] num_to_do = len(to_do) def qt_update_label(text): if not QP.isValid(self) or not QP.isValid( self._export) or not self._export: return self._export.setText(text) def qt_done(quit_afterwards): if not QP.isValid(self) or not QP.isValid( self._export) or not self._export: return self._export.setEnabled(True) if quit_afterwards: QP.CallAfter(self.parentWidget().close) def do_it(directory, neighbouring_txt_tag_service_keys, delete_afterwards, export_symlinks, quit_afterwards): job_key = ClientThreading.JobKey(cancellable=True) job_key.SetStatusTitle('file export') HG.client_controller.pub('message', job_key) pauser = HydrusData.BigJobPauser() for (index, (ordering_index, media, path)) in enumerate(to_do): if job_key.IsCancelled(): break try: x_of_y = HydrusData.ConvertValueRangeToPrettyString( index + 1, num_to_do) job_key.SetVariable('popup_text_1', 'Done {}'.format(x_of_y)) job_key.SetVariable('popup_gauge_1', (index + 1, num_to_do)) QP.CallAfter(qt_update_label, x_of_y) hash = media.GetHash() mime = media.GetMime() path = os.path.normpath(path) if not path.startswith(directory): raise Exception( 'It seems a destination path was above the main export directory! The file was "{}" and its destination path was "{}".' .format(hash.hex(), path)) path_dir = os.path.dirname(path) HydrusPaths.MakeSureDirectoryExists(path_dir) if export_tag_txts: tags_manager = media.GetTagsManager() tags = set() for service_key in neighbouring_txt_tag_service_keys: current_tags = tags_manager.GetCurrent( service_key, ClientTags.TAG_DISPLAY_ACTUAL) tags.update(current_tags) tags = sorted(tags) txt_path = path + '.txt' with open(txt_path, 'w', encoding='utf-8') as f: f.write(os.linesep.join(tags)) source_path = client_files_manager.GetFilePath( hash, mime, check_file_exists=False) if export_symlinks: os.symlink(source_path, path) else: HydrusPaths.MirrorFile(source_path, path) HydrusPaths.MakeFileWriteable(path) except: QP.CallAfter( QW.QMessageBox.information, self, 'Information', 'Encountered a problem while attempting to export file with index ' + str(ordering_index + 1) + ':' + os.linesep * 2 + traceback.format_exc()) break pauser.Pause() if not job_key.IsCancelled() and delete_afterwards: QP.CallAfter(qt_update_label, 'deleting') delete_lock_for_archived_files = HG.client_controller.new_options.GetBoolean( 'delete_lock_for_archived_files') if delete_lock_for_archived_files: deletee_hashes = { media.GetHash() for (ordering_index, media, path) in to_do if not media.HasArchive() } else: deletee_hashes = { media.GetHash() for (ordering_index, media, path) in to_do } chunks_of_hashes = HydrusData.SplitListIntoChunks( deletee_hashes, 64) reason = 'Deleted after manual export to "{}".'.format( directory) content_updates = [ HydrusData.ContentUpdate(HC.CONTENT_TYPE_FILES, HC.CONTENT_UPDATE_DELETE, chunk_of_hashes, reason=reason) for chunk_of_hashes in chunks_of_hashes ] for content_update in content_updates: HG.client_controller.WriteSynchronous( 'content_updates', {CC.LOCAL_FILE_SERVICE_KEY: [content_update]}) job_key.DeleteVariable('popup_gauge_1') job_key.SetVariable('popup_text_1', 'Done!') job_key.Finish() job_key.Delete(5) QP.CallAfter(qt_update_label, 'done!') time.sleep(1) QP.CallAfter(qt_update_label, 'export') QP.CallAfter(qt_done, quit_afterwards) HG.client_controller.CallToThread(do_it, directory, neighbouring_txt_tag_service_keys, delete_afterwards, export_symlinks, quit_afterwards)
def _DoBan( self ): subject_accounts = self._account_panel.GetCheckedAccounts() if len( subject_accounts ) == 0: QW.QMessageBox.information( self, 'Information', 'No accounts selected for action!' ) return some_are_banned = True in ( subject_account.IsBanned() for subject_account in subject_accounts ) if some_are_banned: message = 'Some of these selected accounts are already banned. Sure you want to overwrite the bans?' result = ClientGUIDialogsQuick.GetYesNo( self, message ) if result != QW.QDialog.Accepted: return subject_account_keys = [ subject_account.GetAccountKey() for subject_account in subject_accounts ] reason = self._ban_reason.text() if reason == '': QW.QMessageBox.information( self, 'Information', 'The ban reason is empty!' ) return message = 'Ban these user(s)? All of their pending petitions will be deleted serverside.' result = ClientGUIDialogsQuick.GetYesNo( self, message ) if result != QW.QDialog.Accepted: return expires = self._ban_expires.GetValue() if expires is not None: expires += HydrusData.GetNow() service = self._service def work_callable(): for subject_account_key in subject_account_keys: service.Request( HC.POST, 'modify_account_ban', { 'subject_identifier' : HydrusNetwork.AccountIdentifier( account_key = subject_account_key ), 'reason' : reason, 'expires' : expires } ) return 1 def publish_callable( gumpf ): QW.QMessageBox.information( self, 'Information', 'Done!' ) self._account_panel.RefreshAccounts() self._DisableUIForJob( 'banning\u2026' ) job = ClientGUIAsync.AsyncQtJob( self, work_callable, publish_callable ) job.start()
def _Add(self): external_port = HC.DEFAULT_SERVICE_PORT protocol = 'TCP' internal_port = HC.DEFAULT_SERVICE_PORT description = 'hydrus service' duration = 0 with ClientGUIDialogs.DialogInputUPnPMapping(self, external_port, protocol, internal_port, description, duration) as dlg: if dlg.exec() == QW.QDialog.Accepted: (external_port, protocol, internal_port, description, duration) = dlg.GetInfo() remove_existing = False if self._MappingExists(external_port, protocol): remove_existing = True text = '{}:({}) is already mapped! Ok to overwrite whatever it currently is?' result = ClientGUIDialogsQuick.GetYesNo( self, text, yes_label='do it', no_label='forget it') if result != QW.QDialog.Accepted: return def work_callable(): if remove_existing: HydrusNATPunch.RemoveUPnPMapping( external_port, protocol) internal_client = HydrusNATPunch.GetLocalIP() HydrusNATPunch.AddUPnPMapping(internal_client, internal_port, external_port, protocol, description, duration=duration) return True def publish_callable(result): self._mappings_listctrl_panel.setEnabled(True) self._RefreshMappings() self._mappings_listctrl_panel.setEnabled(False) async_job = ClientGUIAsync.AsyncQtJob(self, work_callable, publish_callable) async_job.start()