Ejemplo n.º 1
0
    def _GetPath(self, media):

        if media in self._media_to_paths:

            return self._media_to_paths[media]

        directory = self._directory_picker.GetPath()

        pattern = self._pattern.text()

        terms = ClientExporting.ParseExportPhrase(pattern)

        filename = ClientExporting.GenerateExportFilename(
            directory,
            media,
            terms,
            do_not_use_filenames=self._existing_filenames)

        path = os.path.join(directory, filename)

        path = os.path.normpath(path)

        self._existing_filenames.add(filename)
        self._media_to_paths[media] = path

        return path
Ejemplo n.º 2
0
    def GetValue(self):

        name = self._name.text()

        path = self._path.GetPath()

        export_type = self._type.GetValue()

        delete_from_client_after_export = self._delete_from_client_after_export.isChecked(
        )

        file_search_context = self._tag_autocomplete.GetFileSearchContext()

        run_regularly = self._run_regularly.isChecked()

        period = self._period.GetValue()

        if self._path.GetPath() in ('', None):

            raise HydrusExceptions.VetoException(
                'You must enter a folder path to export to!')

        phrase = self._pattern.text()

        try:

            ClientExporting.ParseExportPhrase(phrase)

        except Exception as e:

            raise HydrusExceptions.VetoException(
                'Could not parse that export phrase! ' + str(e))

        run_now = self._run_now.isChecked()

        paused = self._paused.isChecked()

        last_error = self._export_folder.GetLastError()

        export_folder = ClientExporting.ExportFolder(
            name,
            path=path,
            export_type=export_type,
            delete_from_client_after_export=delete_from_client_after_export,
            file_search_context=file_search_context,
            run_regularly=run_regularly,
            period=period,
            phrase=phrase,
            last_checked=self._last_checked,
            paused=paused,
            run_now=run_now,
            last_error=last_error)

        return export_folder
Ejemplo n.º 3
0
 def _AddFolder( self ):
     
     new_options = HG.client_controller.new_options
     
     phrase = new_options.GetString( 'export_phrase' )
     
     name = 'export folder'
     path = ''
     export_type = HC.EXPORT_FOLDER_TYPE_REGULAR
     delete_from_client_after_export = False
     file_search_context = ClientSearch.FileSearchContext( file_service_key = CC.LOCAL_FILE_SERVICE_KEY )
     period = 15 * 60
     
     export_folder = ClientExporting.ExportFolder( name, path, export_type = export_type, delete_from_client_after_export = delete_from_client_after_export, file_search_context = file_search_context, period = period, phrase = phrase )
     
     with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit export folder' ) as dlg:
         
         panel = EditExportFolderPanel( dlg, export_folder )
         
         dlg.SetPanel( panel )
         
         if dlg.exec() == QW.QDialog.Accepted:
             
             export_folder = panel.GetValue()
             
             export_folder.SetNonDupeName( self._GetExistingNames() )
             
             self._export_folders.AddDatas( ( export_folder, ) )
Ejemplo n.º 4
0
def DoFileExportDragDrop( window, page_key, media, alt_down ):
    
    drop_source = QG.QDrag( window )
    
    data_object = QMimeDataHydrusFiles()
    
    #
    
    new_options = HG.client_controller.new_options
    
    do_secret_discord_dnd_fix = new_options.GetBoolean( 'secret_discord_dnd_fix' ) and alt_down
    
    #
    
    client_files_manager = HG.client_controller.client_files_manager
    
    original_paths = []
    media_and_original_paths = []
    
    total_size = 0
    
    for m in media:
        
        hash = m.GetHash()
        mime = m.GetMime()
        
        total_size += m.GetSize()
        
        original_path = client_files_manager.GetFilePath( hash, mime, check_file_exists = False )
        
        original_paths.append( original_path )
        media_and_original_paths.append( ( m, original_path ) )
        
    
    #
    
    discord_dnd_fix_possible = new_options.GetBoolean( 'discord_dnd_fix' ) and len( original_paths ) <= 50 and total_size < 200 * 1048576
    
    temp_dir = HG.client_controller.temp_dir
    
    if do_secret_discord_dnd_fix:
        
        dnd_paths = original_paths
        
        flags = QC.Qt.MoveAction
        
    elif discord_dnd_fix_possible and os.path.exists( temp_dir ):
        
        fallback_filename_terms = ClientExporting.ParseExportPhrase( '{hash}' )
        
        try:
            
            filename_pattern = new_options.GetString( 'discord_dnd_filename_pattern' )
            filename_terms = ClientExporting.ParseExportPhrase( filename_pattern )
            
            if len( filename_terms ) == 0:
                
                raise Exception()
                
            
        except:
            
            filename_terms = fallback_filename_terms
            
        
        dnd_paths = []
        
        for ( m, original_path ) in media_and_original_paths:
            
            filename = ClientExporting.GenerateExportFilename( temp_dir, m, filename_terms )
            
            if filename == HC.mime_ext_lookup[ m.GetMime() ]:
                
                filename = ClientExporting.GenerateExportFilename( temp_dir, m, fallback_filename_terms )
                
            
            dnd_path = os.path.join( temp_dir, filename )
            
            if not os.path.exists( dnd_path ):
                
                HydrusPaths.MirrorFile( original_path, dnd_path )
                
            
            dnd_paths.append( dnd_path )
            
        
        flags = QC.Qt.MoveAction | QC.Qt.CopyAction
        
    else:
        
        dnd_paths = original_paths
        flags = QC.Qt.CopyAction
        
    
    uri_list = []
    
    for path in dnd_paths:
        
        uri_list.append( QC.QUrl.fromLocalFile( path ) )
        
    
    data_object.setUrls( uri_list )
    
    #
    
    hashes = [ m.GetHash() for m in media ]
    
    data_object.setHydrusFiles( page_key, hashes )
    
    # old way of doing this that makes some external programs (discord) reject it
    '''
    if page_key is None:
        
        encoded_page_key = None
        
    else:
        
        encoded_page_key = page_key.hex()
        
    
    data_obj = ( encoded_page_key, [ hash.hex() for hash in hashes ] )
    
    data_str = json.dumps( data_obj )
    
    data_bytes = bytes( data_str, 'utf-8' )
    
    data_object.setData( 'application/hydrus-media', data_bytes )
    '''
    #
    
    drop_source.setMimeData( data_object )
    
    result = drop_source.exec_( flags, QC.Qt.CopyAction )
    
    return result
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
    def __init__(self, parent, flat_media, do_export_and_then_quit=False):

        ClientGUIScrolledPanels.ReviewPanel.__init__(self, parent)

        new_options = HG.client_controller.new_options

        self._media_to_paths = {}
        self._existing_filenames = set()
        self._last_phrase_used = ''
        self._last_dir_used = ''

        self._tags_box = ClientGUIListBoxes.StaticBoxSorterForListBoxTags(
            self, 'files\' tags')

        services_manager = HG.client_controller.services_manager

        self._neighbouring_txt_tag_service_keys = services_manager.FilterValidServiceKeys(
            new_options.GetKeyList(
                'default_neighbouring_txt_tag_service_keys'))

        t = ClientGUIListBoxes.ListBoxTagsMedia(self._tags_box,
                                                ClientTags.TAG_DISPLAY_ACTUAL,
                                                include_counts=True)

        self._tags_box.SetTagsBox(t)

        self._tags_box.setMinimumSize(QC.QSize(220, 300))

        self._paths = ClientGUIListCtrl.BetterListCtrl(
            self,
            CGLC.COLUMN_LIST_EXPORT_FILES.ID,
            24,
            self._ConvertDataToListCtrlTuples,
            use_simple_delete=True)

        self._paths.Sort()

        self._export_path_box = ClientGUICommon.StaticBox(self, 'export path')

        self._directory_picker = QP.DirPickerCtrl(self._export_path_box)
        self._directory_picker.dirPickerChanged.connect(self._RefreshPaths)

        self._open_location = QW.QPushButton('open this location',
                                             self._export_path_box)
        self._open_location.clicked.connect(self.EventOpenLocation)

        self._filenames_box = ClientGUICommon.StaticBox(self, 'filenames')

        self._pattern = QW.QLineEdit(self._filenames_box)

        self._update = QW.QPushButton('update', self._filenames_box)
        self._update.clicked.connect(self._RefreshPaths)

        self._examples = ClientGUICommon.ExportPatternButton(
            self._filenames_box)

        self._delete_files_after_export = QW.QCheckBox(
            'delete files from client after export?', self)
        self._delete_files_after_export.setObjectName('HydrusWarning')

        self._export_symlinks = QW.QCheckBox('EXPERIMENTAL: export symlinks',
                                             self)
        self._export_symlinks.setObjectName('HydrusWarning')

        text = 'This will export all the files\' tags, newline separated, into .txts beside the files themselves.'

        self._export_tag_txts_services_button = ClientGUICommon.BetterButton(
            self, 'set .txt services', self._SetTxtServices)

        self._export_tag_txts = QW.QCheckBox('export tags to .txt files?',
                                             self)
        self._export_tag_txts.setToolTip(text)
        self._export_tag_txts.clicked.connect(self.EventExportTagTxtsChanged)

        self._export = QW.QPushButton('export', self)
        self._export.clicked.connect(self._DoExport)

        #

        export_path = ClientExporting.GetExportPath()

        if export_path is not None:

            self._directory_picker.SetPath(export_path)

        phrase = new_options.GetString('export_phrase')

        self._pattern.setText(phrase)

        if len(self._neighbouring_txt_tag_service_keys) > 0:

            self._export_tag_txts.setChecked(True)

        self._paths.SetData(list(enumerate(flat_media)))

        self._delete_files_after_export.setChecked(
            HG.client_controller.new_options.GetBoolean(
                'delete_files_after_export'))
        self._delete_files_after_export.clicked.connect(
            self.EventDeleteFilesChanged)

        if not HG.client_controller.new_options.GetBoolean('advanced_mode'):

            self._export_symlinks.setVisible(False)

        #

        top_hbox = QP.HBoxLayout()

        QP.AddToLayout(top_hbox, self._tags_box, CC.FLAGS_EXPAND_PERPENDICULAR)
        QP.AddToLayout(top_hbox, self._paths, CC.FLAGS_EXPAND_BOTH_WAYS)

        hbox = QP.HBoxLayout()

        QP.AddToLayout(hbox, self._directory_picker, CC.FLAGS_EXPAND_BOTH_WAYS)
        QP.AddToLayout(hbox, self._open_location,
                       CC.FLAGS_CENTER_PERPENDICULAR)

        self._export_path_box.Add(hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR)

        hbox = QP.HBoxLayout()

        QP.AddToLayout(hbox, self._pattern, CC.FLAGS_EXPAND_BOTH_WAYS)
        QP.AddToLayout(hbox, self._update, CC.FLAGS_CENTER_PERPENDICULAR)
        QP.AddToLayout(hbox, self._examples, CC.FLAGS_CENTER_PERPENDICULAR)

        self._filenames_box.Add(hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR)

        txt_hbox = QP.HBoxLayout()

        QP.AddToLayout(txt_hbox, self._export_tag_txts_services_button,
                       CC.FLAGS_CENTER_PERPENDICULAR)
        QP.AddToLayout(txt_hbox, self._export_tag_txts,
                       CC.FLAGS_CENTER_PERPENDICULAR)

        vbox = QP.VBoxLayout()

        QP.AddToLayout(vbox, top_hbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS)
        QP.AddToLayout(vbox, self._export_path_box,
                       CC.FLAGS_EXPAND_PERPENDICULAR)
        QP.AddToLayout(vbox, self._filenames_box,
                       CC.FLAGS_EXPAND_PERPENDICULAR)
        QP.AddToLayout(vbox, self._delete_files_after_export,
                       CC.FLAGS_ON_RIGHT)
        QP.AddToLayout(vbox, self._export_symlinks, CC.FLAGS_ON_RIGHT)
        QP.AddToLayout(vbox, txt_hbox, CC.FLAGS_ON_RIGHT)
        QP.AddToLayout(vbox, self._export, CC.FLAGS_ON_RIGHT)

        self.widget().setLayout(vbox)

        self._RefreshTags()

        self._UpdateTxtButton()

        ClientGUIFunctions.SetFocusLater(self._export)

        self._paths.itemSelectionChanged.connect(self._RefreshTags)

        if do_export_and_then_quit:

            HG.client_controller.CallAfterQtSafe(
                self, 'doing export before dialog quit', self._DoExport, True)
Ejemplo n.º 7
0
    def GetValue(self):

        sidecar_exporter = ClientExporting.SidecarExporter(
            service_keys_to_tag_data=self._service_keys_to_tag_data)

        return sidecar_exporter