diff --git a/plugins/DupFileManager/DupFileManager.py b/plugins/DupFileManager/DupFileManager.py index 2a60215..606ec82 100644 --- a/plugins/DupFileManager/DupFileManager.py +++ b/plugins/DupFileManager/DupFileManager.py @@ -69,6 +69,14 @@ stash = StashPluginHelper( ) stash.convertToAscii = True dry_run = stash.Setting("zzdryRun") +DupFileManagerPyVer = "1.1" + +taskName_deleteScene = "deleteScene" +taskName_copyScene = "copyScene" +taskName_moveScene = "moveScene" +taskName_mergeScene = "mergeScene" +taskName_addExcludeTag = "addExcludeTag" +taskName_clearFlag = "clearFlag" advanceMenuOptions = [ "applyCombo", "applyComboPinklist", "applyComboGraylist", "applyComboBlacklist", "pathToDelete", "pathToDeleteBlacklist", "sizeToDeleteLess", "sizeToDeleteGreater", "sizeToDeleteBlacklistLess", "sizeToDeleteBlacklistGreater", "durationToDeleteLess", "durationToDeleteGreater", "durationToDeleteBlacklistLess", "durationToDeleteBlacklistGreater", "commonResToDeleteLess", "commonResToDeleteEq", "commonResToDeleteGreater", "commonResToDeleteBlacklistLess", "commonResToDeleteBlacklistEq", "commonResToDeleteBlacklistGreater", "resolutionToDeleteLess", "resolutionToDeleteEq", "resolutionToDeleteGreater", @@ -78,8 +86,10 @@ advanceMenuOptions = [ "applyCombo", "applyComboPinklist", "applyComboGraylist" doJsonReturnModeTypes = ["tag_duplicates_task", "removeDupTag", "addExcludeTag", "removeExcludeTag", "mergeTags", "getLocalDupReportPath", "createDuplicateReportWithoutTagging", "deleteLocalDupReportHtmlFiles", "clear_duplicate_tags_task", "deleteAllDupFileManagerTags", "deleteBlackListTaggedDuplicatesTask", "deleteTaggedDuplicatesLwrResOrLwrDuration", - "deleteBlackListTaggedDuplicatesLwrResOrLwrDuration", "create_duplicate_report_task", "copyScene"] + "deleteBlackListTaggedDuplicatesLwrResOrLwrDuration", "create_duplicate_report_task", "copyScene", "renameFile", "deleteScene", + "removeScene", "flagScene", "flagScene", "moveScene"] javascriptModeTypes = ["getReport", "getAdvanceMenu"] +startsWithCommands = [taskName_deleteScene, taskName_copyScene, taskName_moveScene, taskName_mergeScene, taskName_addExcludeTag, taskName_clearFlag] javascriptModeTypes += advanceMenuOptions javascriptModeTypes += doJsonReturnModeTypes doJsonReturn = False @@ -89,6 +99,9 @@ def isReportOrAdvMenu(): return True if stash.PLUGIN_TASK_NAME.endswith("Flag"): return True + for startsWithCommand in startsWithCommands: + if stash.PLUGIN_TASK_NAME.startswith(startsWithCommand): + return True return False if isReportOrAdvMenu(): @@ -160,6 +173,8 @@ reportHeader = f"{DupFileManagerFolder}{os.sep}DupFileManager_rep excludeFromReportIfSignificantTimeDiff = False htmlReportPaginate = stash.Setting('htmlReportPaginate') +htmlIncludeCoverImage = stash.Setting('htmlIncludeCoverImage') +htmlIncludeWebpPreview = stash.Setting('htmlIncludeWebpPreview') htmlIncludeImagePreview = stash.Setting('htmlIncludeImagePreview') htmlIncludeVideoPreview = stash.Setting('htmlIncludeVideoPreview') htmlHighlightTimeDiff = stash.Setting('htmlHighlightTimeDiff') @@ -220,6 +235,15 @@ if (stash.PLUGIN_TASK_NAME == "tag_duplicates_task" or stash.PLUGIN_TASK_NAME == htmlIncludeVideoPreview = True else: htmlIncludeVideoPreview = False + if len(targets) > 18: + if targets[17] == "true": + htmlIncludeWebpPreview = True + else: + htmlIncludeWebpPreview = False + if targets[18] == "true": + htmlIncludeCoverImage = True + else: + htmlIncludeCoverImage = False logTraceForAdvanceMenuOpt = True if htmlIncludeImagePreview and (htmlImagePreviewSize == htmlImagePreviewPopupSize): @@ -242,7 +266,7 @@ if significantTimeDiff < .25: significantTimeDiff = float(0.25) if logTraceForAdvanceMenuOpt: - stash.Trace(f"PLUGIN_TASK_NAME={stash.PLUGIN_TASK_NAME}; matchDupDistance={matchDupDistance}; matchPhaseDistanceText={matchPhaseDistanceText}; matchPhaseDistance={matchPhaseDistance}; significantTimeDiff={significantTimeDiff}; htmlReportPaginate={htmlReportPaginate}; htmlIncludeImagePreview={htmlIncludeImagePreview}; htmlIncludeVideoPreview={htmlIncludeVideoPreview}; maxDupToProcess={maxDupToProcess}; htmlHighlightTimeDiff={htmlHighlightTimeDiff}; htmlImagePreviewSize={htmlImagePreviewSize}; htmlImagePreviewPopupSize={htmlImagePreviewPopupSize}; htmlImagePreviewPopupEnable={htmlImagePreviewPopupEnable}; htmlPreviewOrStream={htmlPreviewOrStream};") + stash.Trace(f"PLUGIN_TASK_NAME={stash.PLUGIN_TASK_NAME}; matchDupDistance={matchDupDistance}; matchPhaseDistanceText={matchPhaseDistanceText}; matchPhaseDistance={matchPhaseDistance}; significantTimeDiff={significantTimeDiff}; htmlReportPaginate={htmlReportPaginate}; htmlIncludeCoverImage={htmlIncludeCoverImage}; htmlIncludeImagePreview={htmlIncludeImagePreview}; htmlIncludeVideoPreview={htmlIncludeVideoPreview}; maxDupToProcess={maxDupToProcess}; htmlHighlightTimeDiff={htmlHighlightTimeDiff}; htmlImagePreviewSize={htmlImagePreviewSize}; htmlImagePreviewPopupSize={htmlImagePreviewPopupSize}; htmlImagePreviewPopupEnable={htmlImagePreviewPopupEnable}; htmlPreviewOrStream={htmlPreviewOrStream};") duplicateMarkForDeletion = stash.Setting('DupFileTag') if duplicateMarkForDeletion == "": @@ -576,7 +600,7 @@ def getPath(Scene, getParent = False): path = path.replace("'", "") path = path.replace("\\\\", "\\") if getParent: - return pathlib.Path(path).resolve().parent + return pathlib.Path(path).parent return path htmlReportPrefix = None @@ -678,6 +702,26 @@ itemIndexSrchStr = "::itemIndex=" ToDeleteSceneIDSrchStr = "\n") fragmentForSceneDetails = 'id tags {id name ignore_auto_tag} groups {group {name} } performers {name} galleries {id} files {path width height duration size video_codec bit_rate frame_rate} details ' -htmlFileData = " paths {screenshot sprite " + htmlPreviewOrStream + "} " +htmlFileData = " paths {screenshot sprite webp " + htmlPreviewOrStream + "} " mergeFieldData = " code director title rating100 date studio {id name} urls " fragmentForSceneDetails += mergeFieldData + htmlFileData DuplicateCandidateForDeletionList = f"{htmlReportNameFolder}{os.sep}DuplicateCandidateForDeletionList.txt" @@ -1266,7 +1291,7 @@ def mangeDupFiles(merge=False, deleteDup=False, tagDuplicates=False, deleteBlack stash.optimise_database() if doGeneratePhash: stash.metadata_generate({"phashes": True}) - sys.stdout.write("Report complete") + sys.stdout.write(f"{{'Report-Status' : 'Report complete', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") def findCurrentTagId(tagNames): # tagNames = [i for n, i in enumerate(tagNames) if i not in tagNames[:n]] @@ -1681,7 +1706,7 @@ def removeDupTag(): stash.Log(f"Processing scene ID# {scene}") stash.removeTag(scene, duplicateMarkForDeletion) stash.Log(f"Done removing tag from scene {scene}.") - jsonReturn = "{'removeDupTag' : 'complete', 'id': '" + f"{scene}" + "'}" + jsonReturn = f"{{'removeDupTag' : 'complete', 'id': '{scene}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}" stash.Log(f"Sending json value {jsonReturn}") sys.stdout.write(jsonReturn) @@ -1693,7 +1718,7 @@ def addExcludeTag(): stash.Log(f"Processing scene ID# {scene}") stash.addTag(scene, excludeDupFileDeleteTag) stash.Log(f"Done adding exclude tag to scene {scene}.") - sys.stdout.write("{" + f"addExcludeTag : 'complete', id: '{scene}'" + "}") + sys.stdout.write(f"{{'addExcludeTag' : 'complete', 'id': '{scene}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") def removeExcludeTag(): if 'Target' not in stash.JSON_INPUT['args']: @@ -1703,7 +1728,7 @@ def removeExcludeTag(): stash.Log(f"Processing scene ID# {scene}") stash.removeTag(scene, excludeDupFileDeleteTag) stash.Log(f"Done removing exclude tag from scene {scene}.") - sys.stdout.write("{" + f"removeExcludeTag : 'complete', id: '{scene}'" + "}") + sys.stdout.write(f"{{'removeExcludeTag' : 'complete', 'id': '{scene}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") def getParseData(getSceneDetails1=True, getSceneDetails2=True, checkIfNotSplitValue=False): if 'Target' not in stash.JSON_INPUT['args']: @@ -1754,7 +1779,7 @@ def mergeMetadataForAll(ReportName = htmlReportName): break mergeMetadataInThisFile(fileName) stash.Log(f"Done merging metadata for all scenes") - sys.stdout.write("{mergeTags : 'complete'}") + sys.stdout.write(f"{{'mergeTags' : 'complete', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") # ToDo: Rename mergeTags to mergeMetadata def mergeTags(inputScene1=None): @@ -1764,7 +1789,7 @@ def mergeTags(inputScene1=None): if scene1 == "mergeMetadataForAll": mergeMetadataForAll() else: - sys.stdout.write("{" + f"mergeTags : 'failed', id1: '{scene1}', id2: '{scene2}'" + "}") + sys.stdout.write(f"{{'mergeTags' : 'failed', 'id1': '{scene1}', 'id2': '{scene2}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") return else: scene1 = inputScene1 @@ -1773,7 +1798,7 @@ def mergeTags(inputScene1=None): updateScenesInReports(scene2['id']) stash.Log(f"Done merging scenes for scene {scene1['id']} and scene {scene2['id']}") if inputScene1 == None: - sys.stdout.write("{" + f"mergeTags : 'complete', id1: '{scene1['id']}', id2: '{scene2['id']}'" + "}") + sys.stdout.write(f"{{'mergeTags' : 'complete', 'id1': '{scene1['id']}', 'id2': '{scene2['id']}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") def getLocalDupReportPath(): htmlReportExist = "true" if os.path.isfile(htmlReportName) else "false" @@ -1785,7 +1810,7 @@ def getLocalDupReportPath(): apikey_json = ", 'apiKey':''" if 'apiKey' in stash.STASH_CONFIGURATION: apikey_json = f", 'apiKey':'{stash.STASH_CONFIGURATION['apiKey']}'" - jsonReturn = "{" + f"'LocalDupReportExist' : {htmlReportExist}, 'Path': '{localPath}', 'LocalDir': '{LocalDir}', 'ReportUrlDir': '{ReportUrlDir}', 'ReportUrl': '{ReportUrl}', 'AdvMenuUrl': '{AdvMenuUrl}', 'IS_DOCKER': '{stash.IS_DOCKER}', 'remoteReportDirURL': '{stash.Setting('remoteReportDirURL')}' {apikey_json}" + "}" + jsonReturn = f"{{'LocalDupReportExist' : {htmlReportExist}, 'Path': '{localPath}', 'LocalDir': '{LocalDir}', 'ReportUrlDir': '{ReportUrlDir}', 'ReportUrl': '{ReportUrl}', 'AdvMenuUrl': '{AdvMenuUrl}', 'IS_DOCKER': '{stash.IS_DOCKER}', 'remoteReportDirURL': '{stash.Setting('remoteReportDirURL')}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}' {apikey_json}}}" stash.Log(f"Sending json value {jsonReturn}") sys.stdout.write(jsonReturn) @@ -1804,7 +1829,7 @@ def deleteLocalDupReportHtmlFiles(doJsonOutput = True): else: stash.Log(f"Report file does not exist: {htmlReportName}") if doJsonOutput: - jsonReturn = "{'LocalDupReportExist' : " + f"{htmlReportExist}" + ", 'Path': '" + f"{htmlReportName}" + "', 'qty': '" + f"{x}" + "'}" + jsonReturn = f"{{'LocalDupReportExist' : {htmlReportExist}, 'Path': '{htmlReportName}', 'qty': '{x}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}" stash.Log(f"Sending json value {jsonReturn}") sys.stdout.write(jsonReturn) @@ -1836,7 +1861,7 @@ def removeAllDupTagsFromAllScenes(deleteTags=False): if removeTagFromAllScenes(tagToClear, deleteTags): validTags +=[tagToClear] if doJsonReturn: - jsonReturn = "{'removeAllDupTagFromAllScenes' : " + f"{duplicateMarkForDeletion}" + ", 'OtherTags': '" + f"{validTags}" + "'}" + jsonReturn = f"{{'removeAllDupTagFromAllScenes' : '{duplicateMarkForDeletion}', 'OtherTags': '{validTags}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}" stash.Log(f"Sending json value {jsonReturn}") sys.stdout.write(jsonReturn) else: @@ -2024,19 +2049,19 @@ def deleteScene(disableInReport=True, deleteFile=True, scene=None, writeToStdOut modifyPropertyToSceneClassToAllFiles(f"{scene}_preview", "{display:none;}") if writeToStdOut: stash.Log(f"{stash.PLUGIN_TASK_NAME} complete for scene {scene} with results = {result}") - sys.stdout.write("{" + f"{stash.PLUGIN_TASK_NAME} : 'complete', id: '{scene}', result: '{result}'" + "}") + sys.stdout.write(f"{{'{stash.PLUGIN_TASK_NAME}' : 'complete', 'id': '{scene}', 'result': '{result}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") return result def clearAllSceneFlags(flagColor=None): modifyPropertyToSceneClassToAllFiles(None, flagColor) stash.Log(f"{stash.PLUGIN_TASK_NAME} complete for all scenes") - sys.stdout.write("{" + f"{stash.PLUGIN_TASK_NAME} : 'complete'" + "}") + sys.stdout.write(f"{{'{stash.PLUGIN_TASK_NAME}' : 'complete', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") def copyScene(moveScene=False, inputScene1=None): if inputScene1 == None: scene1, scene2 = getParseData() if scene1 == None or scene2 == None: - sys.stdout.write("{" + f"{stash.PLUGIN_TASK_NAME} : 'failed', id1: '{scene1}', id2: '{scene2}'" + "}") + sys.stdout.write(f"{{'{stash.PLUGIN_TASK_NAME}' : 'failed', 'id1': '{scene1}', 'id2': '{scene2}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") return else: scene1 = inputScene1 @@ -2061,16 +2086,16 @@ def copyScene(moveScene=False, inputScene1=None): updateScenesInReports(scene2['id']) stash.Log(f"{actionStr} complete for scene {scene1['id']} and {scene2['id']}") if inputScene1 == None: - sys.stdout.write("{" + f"{stash.PLUGIN_TASK_NAME} : 'complete', id1: '{scene1['id']}', id2: '{scene2['id']}', result: '{result}'" + "}") + sys.stdout.write(f"{{'{stash.PLUGIN_TASK_NAME}' : 'complete', 'id1': '{scene1['id']}', 'id2': '{scene2['id']}', 'result': '{result}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") def renameFile(): scene, newName = getParseData(getSceneDetails2=False) if scene == None or newName == None: - sys.stdout.write("{" + f"{stash.PLUGIN_TASK_NAME} : 'failed', scene: '{scene}', newName: '{newName}'" + "}") + sys.stdout.write(f"{{'{stash.PLUGIN_TASK_NAME}' : 'failed', 'scene': '{scene}', 'newName': '{newName}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") return newName = newName.strip("'") ext = pathlib.Path(scene['files'][0]['path']).suffix - newNameFull = f"{pathlib.Path(scene['files'][0]['path']).resolve().parent}{os.sep}{newName}{ext}" + newNameFull = f"{pathlib.Path(scene['files'][0]['path']).parent}{os.sep}{newName}{ext}" newNameFull = newNameFull.strip("'") newNameFull = newNameFull.replace("\\\\", "\\") oldNameFull = scene['files'][0]['path'] @@ -2080,13 +2105,14 @@ def renameFile(): result = os.rename(oldNameFull, newNameFull) stash.renameFileNameInDB(scene['files'][0]['id'], pathlib.Path(oldNameFull).stem, f"{newName}{ext}", UpdateUsingIdOnly = True) updateScenesInReports(scene['id']) - stash.Log(f"{stash.PLUGIN_TASK_NAME} complete for scene {scene['id']} ;renamed to {newName}; result={result}") - sys.stdout.write("{" + f"{stash.PLUGIN_TASK_NAME} : 'complete', scene: '{scene['id']}', newName: '{newName}', result: '{result}'" + "}") + stash.Log(f"{stash.PLUGIN_TASK_NAME} complete for scene {scene['id']} ;renamed to {newNameFull}; result={result}") + # newNameFull = newNameFull.replace("\\", "\\\\") + sys.stdout.write(f"{{'{stash.PLUGIN_TASK_NAME}' : 'complete', 'scene': '{scene['id']}', 'newName': '{newNameFull}', 'result': '{result}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") def flagScene(): scene, flagType = getParseData(False, False) if scene == None or flagType == None: - sys.stdout.write("{" + f"{stash.PLUGIN_TASK_NAME} : 'failed', scene: '{scene}', flagType: '{flagType}'" + "}") + sys.stdout.write(f"{{'{stash.PLUGIN_TASK_NAME}' : 'failed', 'scene': '{scene}', 'flagType': '{flagType}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") return if " highlight" in flagType: @@ -2112,9 +2138,9 @@ def flagScene(): modifyPropertyToSceneClassToAllFiles(scene, "") else: stash.Log(f"Invalid flagType ({flagType})") - sys.stdout.write("{" + f"{stash.PLUGIN_TASK_NAME} : 'failed', scene: '{scene}', flagType: '{flagType}'" + "}") + sys.stdout.write(f"{{'{stash.PLUGIN_TASK_NAME}' : 'failed', 'scene': '{scene}', 'flagType': '{flagType}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") return - sys.stdout.write("{" + f"{stash.PLUGIN_TASK_NAME} : 'complete', scene: '{scene}', flagType: '{flagType}'" + "}") + sys.stdout.write(f"{{'{stash.PLUGIN_TASK_NAME}' : 'complete', 'scene': '{scene}', 'flagType': '{flagType}', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") def getReport(): if 'Target' not in stash.JSON_INPUT['args']: @@ -2157,12 +2183,6 @@ def getAdvanceMenu(): # Remove only graylist dup # Exclude graylist from delete # Include graylist in delete -taskName_deleteScene = "deleteScene" -taskName_copyScene = "copyScene" -taskName_moveScene = "moveScene" -taskName_mergeScene = "mergeScene" -taskName_addExcludeTag = "addExcludeTag" -taskName_clearFlag = "clearFlag" try: if stash.PLUGIN_TASK_NAME == "tag_duplicates_task": @@ -2307,6 +2327,7 @@ except Exception as e: stash.convertToAscii = False stash.Error(f"Error: {e}\nTraceBack={tb}") if doJsonReturn: - sys.stdout.write("{" + f"Exception : '{e}; See log file for TraceBack' " + "}") + errStr = e.replace("'", "`") + sys.stdout.write(f"{{'Exception' : '{errStr}; See log file for TraceBack', 'DupFileManagerPyVer': '{DupFileManagerPyVer}'}}") stash.Log("\n*********************************\nEXITING ***********************\n*********************************") diff --git a/plugins/DupFileManager/DupFileManager.yml b/plugins/DupFileManager/DupFileManager.yml index b7fc603..38e19cf 100644 --- a/plugins/DupFileManager/DupFileManager.yml +++ b/plugins/DupFileManager/DupFileManager.yml @@ -1,6 +1,6 @@ name: DupFileManager description: Manages duplicate files. -version: 1.1.5 +version: 1.1.6 beta url: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/DupFileManager ui: # css: diff --git a/plugins/DupFileManager/DupFileManager_report.js b/plugins/DupFileManager/DupFileManager_report.js index 2bf9ec6..2ce57e0 100644 --- a/plugins/DupFileManager/DupFileManager_report.js +++ b/plugins/DupFileManager/DupFileManager_report.js @@ -10,6 +10,7 @@ console.log("Cookies = " + document.cookie); const StrRemoveToKeepConfirm = "RemoveToKeepConfirm="; const StrRemoveValidatePrompt = "RemoveValidatePrompt="; const StrDisableReloadPage = "DisableReloadPage="; +var DupFileManagerPyVer = null; function SetPaginateButtonChange(){ var chkBxRemoveValid = document.getElementById("RemoveValidatePrompt"); var chkBxDisableDeleteConfirm = document.getElementById("RemoveToKeepConfirm"); @@ -18,9 +19,9 @@ function SetPaginateButtonChange(){ RemoveValidatePromptValue = StrRemoveValidatePrompt + "false"; DisableReloadPageValue = StrDisableReloadPage + "false"; if (chkBxRemoveValid.checked) - RemoveToKeepConfirmValue = StrRemoveToKeepConfirm + "true"; - if (chkBxDisableDeleteConfirm.checked) RemoveValidatePromptValue = StrRemoveValidatePrompt + "true"; + if (chkBxDisableDeleteConfirm.checked) + RemoveToKeepConfirmValue = StrRemoveToKeepConfirm + "true"; if (chkBxDisableReloadPage != null && chkBxDisableReloadPage.checked) DisableReloadPageValue = StrDisableReloadPage + "true"; document.cookie = RemoveToKeepConfirmValue + "&" + RemoveValidatePromptValue + "&" + DisableReloadPageValue + "; SameSite=None; Secure"; @@ -32,6 +33,17 @@ function trim(str, ch) { while(end > start && str[end - 1] === ch) --end; return (start > 0 || end < str.length) ? str.substring(start, end) : str; } +function GetRunPluginOperationJson(result){ + try{ + jsonResults = JSON.parse(result); + const jsonSubResults = JSON.parse(jsonResults.data.runPluginOperation.replaceAll("'", "\"").replaceAll("\\", "\\\\")); + DupFileManagerPyVer = jsonSubResults.DupFileManagerPyVer + return jsonSubResults; + }catch(error){ + console.error(error); + } + return null; +} function RunPluginOperation(Mode, ActionID, button, asyncAjax){ // Mode=Value and ActionID=id if (Mode == null || Mode === ""){ console.log("Error: Mode is empty or null; ActionID = " + ActionID); @@ -49,16 +61,26 @@ function RunPluginOperation(Mode, ActionID, button, asyncAjax){ // Mode=Value an query: `mutation RunPluginOperation($plugin_id:ID!,$args:Map!){runPluginOperation(plugin_id:$plugin_id,args:$args)}`, variables: {"plugin_id": "DupFileManager", "args": { "Target" : ActionID, "mode":Mode}}, }), success: function(result){ - console.log(result); + console.log("For ActionID '" + ActionID + "' result=" + result); + const jsonSubResults = GetRunPluginOperationJson(result); if (asyncAjax){ $('html').removeClass('wait'); $("body").css("cursor", "default"); } - if (Mode.startsWith("copyScene") || Mode.startsWith("renameFile") || Mode === "clearAllSceneFlags" || Mode.startsWith("clearFlag") || Mode.startsWith("mergeScene") || Mode.startsWith("mergeTags") || (Mode !== "deleteScene" && Mode.startsWith("deleteScene"))){ + if (Mode === "deleteScene" || Mode === "removeScene"){ + console.log("Delete complete. Setting background color for .ID_" + ActionID); + $('.ID_' + ActionID).css('background-color','gray'); + } + else if (Mode === "renameFile" && jsonSubResults != null){ + const FnId = ".FN_ID_" + jsonSubResults.scene; + console.log("Changing existing file name ID (" + FnId + ") '" + $(FnId).text() + "' to '" + jsonSubResults.newName + "'"); + $(FnId).text(jsonSubResults.newName); + }else if (Mode.startsWith("copyScene") || Mode.startsWith("renameFile") || Mode === "clearAllSceneFlags" || Mode.startsWith("clearFlag") || Mode.startsWith("mergeScene") || Mode.startsWith("mergeTags") || (Mode !== "deleteScene" && Mode.startsWith("deleteScene"))){ const chkBxDisableReloadPage = document.getElementById("DisableReloadPage"); if (chkBxDisableReloadPage == null || !chkBxDisableReloadPage.checked) window.location.reload(); - } else if (!chkBxRemoveValid.checked && Mode !== "flagScene") alert("Action " + Mode + " for scene(s) ID# " + ActionID + " complete.\\n\\nResults=" + result); + } else if (!chkBxRemoveValid.checked && Mode !== "flagScene") + alert("Action " + Mode + " for scene(s) ID# " + ActionID + " complete.\\n\\nResults=" + result); }, error: function(XMLHttpRequest, textStatus, errorThrown) { console.log("Ajax failed with Status: " + textStatus + "; Error: " + errorThrown); if (asyncAjax){ @@ -218,7 +240,7 @@ $(document).ready(function(){ if (!chkBxDisableDeleteConfirm.checked && !confirm(question)) return; if (Mode === "deleteScene" || Mode === "removeScene"){ - $('.ID_' + ActionID).css('background-color','gray'); + // $('.ID_' + ActionID).css('background-color','gray'); $('.ID_' + ActionID).css('pointer-events','none'); } } diff --git a/plugins/DupFileManager/DupFileManager_report_config.py b/plugins/DupFileManager/DupFileManager_report_config.py index 1d0bc4f..2692741 100644 --- a/plugins/DupFileManager/DupFileManager_report_config.py +++ b/plugins/DupFileManager/DupFileManager_report_config.py @@ -7,6 +7,10 @@ report_config = { # Paginate HTML report. Maximum number of results to display on one page, before adding (paginating) an additional page. "htmlReportPaginate" : 100, + # If enabled, report displays the scene cover as a preview image + "htmlIncludeCoverImage" : False, + # If enabled, report displays Webp as a preview image + "htmlIncludeWebpPreview" : False, # If enabled, report displays an image preview similar to sceneDuplicateChecker "htmlIncludeImagePreview" : False, "htmlImagePreviewSize" : 140, diff --git a/plugins/DupFileManager/README.md b/plugins/DupFileManager/README.md index 602c9b8..82a7f07 100644 --- a/plugins/DupFileManager/README.md +++ b/plugins/DupFileManager/README.md @@ -1,4 +1,4 @@ -# DupFileManager: Ver 1.1.5 (By David Maisonave) +# DupFileManager: Ver 1.1.6 beta (By David Maisonave) DupFileManager is a [Stash](https://github.com/stashapp/stash) plugin which manages duplicate files in the Stash system. It has both **task** and **tools-UI** components. @@ -135,7 +135,6 @@ Users can setup a private or alternate remote site by changing variables **remot - Scheduled Changes - Remove [Max Dup Process] from the Stash->Plugins GUI. This option already exist in advance menu. Planned for 1.2.0 Version. - Add chat icon to report which on hover, displays a popup window showing scene details content. Planned for 1.2.0 Version. - - Add image icon to report; on hover show scene cover image. Planned for 1.2.0 Version. - Add studio icon to report; on hover show studio name. Planned for 1.2.0 Version. - Add option on report to view rating and change it. Use an icon with a number on it to show rating. Planned for 1.2.0 Version. - On report make flag toggle logic. In other words, when flag button is selected, and scene is already that color, remove the colored flag. Planned for 1.2.0 Version. diff --git a/plugins/DupFileManager/advance_options.html b/plugins/DupFileManager/advance_options.html index d914edb..037f788 100644 --- a/plugins/DupFileManager/advance_options.html +++ b/plugins/DupFileManager/advance_options.html @@ -69,7 +69,7 @@ function RunPluginDupFileManager(Mode, Param = 0, Async = false, TagOnlyScenes = } console.log("Ajax success with result = " + result); if (Mode === "tag_duplicates_task" || Mode === "create_duplicate_report_task"){ - if (result.indexOf("\"Report complete\"") == -1) + if (result.indexOf("Report complete") == -1) alert("Stash RunPluginOperation returned unexpected results.\nNot sure if report completed successfully.\n\nResults = " + result); else{ var Notice = ""; @@ -128,7 +128,7 @@ function GetStashTabUrl(Tab){ function GetReportCreateOptions(Value){ if (Value === "-1") return ""; - const param = Value + ":" + $("#significantTimeDiff").val() + ":" + $("#IncludePreviewImage").prop('checked') + ":" + $("#scenesPerPage").val() + ":" + $("#ImagePreviewSize").val() + ":" + $("#ImagePreviewPopupSize").val() + ":" + $("#TimeDiffHighlight").val() + ":" + $("#maxDupToProcess").val() + ":" + $("#streamOverPreview").prop('checked') + ":" + $("#SupperHighlight").val() + ":" + $("#DetailDiffTextColor").val() + ":" + $("#LowerHighlight").val() + ":" + $("#ReportBackgroundColor").val() + ":" + $("#ReportTextColor").val() + ":" + $("#VideoPreviewWidth").val() + ":" + $("#VideoPreviewHeight").val() + ":" + $("#IncludePreviewVideo").prop('checked'); + const param = Value + ":" + $("#significantTimeDiff").val() + ":" + $("#IncludePreviewImage").prop('checked') + ":" + $("#scenesPerPage").val() + ":" + $("#ImagePreviewSize").val() + ":" + $("#ImagePreviewPopupSize").val() + ":" + $("#TimeDiffHighlight").val() + ":" + $("#maxDupToProcess").val() + ":" + $("#streamOverPreview").prop('checked') + ":" + $("#SupperHighlight").val() + ":" + $("#DetailDiffTextColor").val() + ":" + $("#LowerHighlight").val() + ":" + $("#ReportBackgroundColor").val() + ":" + $("#ReportTextColor").val() + ":" + $("#VideoPreviewWidth").val() + ":" + $("#VideoPreviewHeight").val() + ":" + $("#IncludePreviewVideo").prop('checked') + ":" + $("#IncludeWebpPreviewImage").prop('checked') + ":" + $("#IncludeSceneCoverPreviewImage").prop('checked'); console.log("param = " + param); return param; } @@ -294,19 +294,24 @@ $(document).ready(function(){ $("#ImagePreviewPopupSize").prop('disabled', false); } else{ - $("#ImagePreviewSize").prop('disabled', true); + if ($("#IncludeSceneCoverPreviewImage").prop('checked')) + $("#ImagePreviewSize").prop('disabled', false); + else + $("#ImagePreviewSize").prop('disabled', true); $("#ImagePreviewPopupSize").prop('disabled', true); } - if ($("#IncludePreviewVideo").prop('checked')){ - $("#streamOverPreview").prop('disabled', false); + if ($("#IncludePreviewVideo").prop('checked') || $("#IncludeWebpPreviewImage").prop('checked')){ $("#VideoPreviewWidth").prop('disabled', false); $("#VideoPreviewHeight").prop('disabled', false); } else{ - $("#streamOverPreview").prop('disabled', true); $("#VideoPreviewWidth").prop('disabled', true); $("#VideoPreviewHeight").prop('disabled', true); } + if ($("#IncludePreviewVideo").prop('checked')) + $("#streamOverPreview").prop('disabled', false); + else + $("#streamOverPreview").prop('disabled', true); $("button").click(function(){ ProcessClick(this); }); @@ -324,10 +329,19 @@ $(document).ready(function(){ $("#ImagePreviewPopupSize").prop('disabled', false); } else{ - $("#ImagePreviewSize").prop('disabled', true); + if ($("#IncludeSceneCoverPreviewImage").prop('checked')) + $("#ImagePreviewSize").prop('disabled', false); + else + $("#ImagePreviewSize").prop('disabled', true); $("#ImagePreviewPopupSize").prop('disabled', true); } }); + $("#IncludeSceneCoverPreviewImage").change(function() { + if(this.checked || $("#IncludePreviewImage").prop('checked')) + $("#ImagePreviewSize").prop('disabled', false); + else + $("#ImagePreviewSize").prop('disabled', true); + }); $("#IncludePreviewVideo").change(function() { if(this.checked){ $("#streamOverPreview").prop('disabled', false); @@ -336,6 +350,22 @@ $(document).ready(function(){ } else{ $("#streamOverPreview").prop('disabled', true); + if ($("#IncludeWebpPreviewImage").prop('checked')){ + $("#VideoPreviewWidth").prop('disabled', false); + $("#VideoPreviewHeight").prop('disabled', false); + } + else { + $("#VideoPreviewWidth").prop('disabled', true); + $("#VideoPreviewHeight").prop('disabled', true); + } + } + }); + $("#IncludeWebpPreviewImage").change(function() { + if(this.checked || $("#IncludePreviewVideo").prop('checked')){ + $("#VideoPreviewWidth").prop('disabled', false); + $("#VideoPreviewHeight").prop('disabled', false); + } + else{ $("#VideoPreviewWidth").prop('disabled', true); $("#VideoPreviewHeight").prop('disabled', true); } @@ -2023,13 +2053,14 @@ function DeleteDupInPath(){ -
+
+
-
+
-
+
@@ -2061,7 +2092,8 @@ function DeleteDupInPath(){ -
+
+
@@ -2204,4 +2236,3 @@ function DeleteDupInPath(){
- diff --git a/plugins/DupFileManager/version_history/README.md b/plugins/DupFileManager/version_history/README.md index 18cc7c8..ed4682b 100644 --- a/plugins/DupFileManager/version_history/README.md +++ b/plugins/DupFileManager/version_history/README.md @@ -108,5 +108,15 @@ ### 1.1.5 - After deleting scene from report, disable preview for the deleted scene on the report. - Add option to report to avoid reloading page after updating report. +### 1.1.6 beta +Note: This is a beta version, because not all of the javascript ajax functions have been tested yet. +- Added the following to [**Advance Duplicate File Menu**] + - Scene cover preview image option + - Webp preview video option +- Fix json string return for all calls made from javascript. +- Added DupFileManagerPyVer field to json when called from javascript. +- When deleting scene using Report, replaced completion prompt with scene background set to gray. +- In Report, when rename occurs, the scene gets renamed inline, without having to reload report page. +- Added GetRunPluginOperationJson to DupFileManager_report.js which allows result to safely be converted to json. If fails, it gracefully returns null.