'
dupFileExist = True if os.path.isfile(DupFile['files'][0]['path']) else False
toKeepFileExist = True if os.path.isfile(DupFileToKeep['files'][0]['path']) else False
fileHtmlReport.write(f"{htmlReportTableRow}")
@@ -611,6 +619,29 @@ def writeRowToHtmlReport(fileHtmlReport, DupFile, DupFileToKeep, QtyTagForDel =
fileHtmlReport.write(f"[Play]")
else:
fileHtmlReport.write("[File NOT Exist]")
+ if len(DupFile['tags']) > 0:
+ fileHtmlReport.write(htmlTagPrefix)
+ for tag in DupFile['tags']:
+ # if not tag['ignore_auto_tag']:
+ fileHtmlReport.write(f"
{tag['name']}
")
+ fileHtmlReport.write("
")
+ if len(DupFile['performers']) > 0:
+ fileHtmlReport.write(htmlPerformerPrefix)
+ for performer in DupFile['performers']:
+ fileHtmlReport.write(f"
{performer['name']}
")
+ fileHtmlReport.write("
")
+ if len(DupFile['galleries']) > 0:
+ fileHtmlReport.write(htmlGalleryPrefix)
+ for gallery in DupFile['galleries']:
+ gallery = stash.find_gallery(gallery['id'])
+ fileHtmlReport.write(f"
{gallery['title']}
")
+ fileHtmlReport.write("
")
+ if len(DupFile['groups']) > 0:
+ fileHtmlReport.write(htmlGroupPrefix)
+ for group in DupFile['groups']:
+ fileHtmlReport.write(f"
{group['group']['name']}
")
+ fileHtmlReport.write("
")
+
fileHtmlReport.write("")
videoPreview = f""
@@ -633,14 +664,41 @@ def writeRowToHtmlReport(fileHtmlReport, DupFile, DupFileToKeep, QtyTagForDel =
else:
fileHtmlReport.write("[File NOT Exist]")
fileHtmlReport.write(f"")
+ if len(DupFileToKeep['tags']) > 0:
+ fileHtmlReport.write(htmlTagPrefix)
+ for tag in DupFileToKeep['tags']:
+ # if not tag['ignore_auto_tag']:
+ fileHtmlReport.write(f"
{tag['name']}
")
+ fileHtmlReport.write("")
+ if len(DupFileToKeep['performers']) > 0:
+ fileHtmlReport.write(htmlPerformerPrefix)
+ for performer in DupFileToKeep['performers']:
+ fileHtmlReport.write(f"
{performer['name']}
")
+ fileHtmlReport.write("")
+ if len(DupFileToKeep['galleries']) > 0:
+ fileHtmlReport.write(htmlGalleryPrefix)
+ for gallery in DupFileToKeep['galleries']:
+ gallery = stash.find_gallery(gallery['id'])
+ fileHtmlReport.write(f"
{gallery['title']}
")
+ fileHtmlReport.write("")
+ if len(DupFileToKeep['groups']) > 0:
+ fileHtmlReport.write(htmlGroupPrefix)
+ for group in DupFileToKeep['groups']:
+ fileHtmlReport.write(f"
{group['group']['name']}
")
+ fileHtmlReport.write("")
# ToDo: Add following buttons:
# rename file
fileHtmlReport.write(f"")
fileHtmlReport.write("\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 + "} "
+DuplicateCandidateForDeletionList = f"{htmlReportNameFolder}{os.sep}DuplicateCandidateForDeletionList.txt"
+
def mangeDupFiles(merge=False, deleteDup=False, tagDuplicates=False, deleteBlacklistOnly=False, deleteLowerResAndDuration=False):
global reasonDict
+ global htmlFileData
duplicateMarkForDeletion_descp = 'Tag added to duplicate scenes so-as to tag them for deletion.'
stash.Trace(f"duplicateMarkForDeletion = {duplicateMarkForDeletion}")
dupTagId = stash.createTagId(duplicateMarkForDeletion, duplicateMarkForDeletion_descp, ignoreAutoTag=True)
@@ -671,27 +729,29 @@ def mangeDupFiles(merge=False, deleteDup=False, tagDuplicates=False, deleteBlack
stash.Trace("#########################################################################")
stash.Log(f"Waiting for find_duplicate_scenes_diff to return results; matchDupDistance={matchPhaseDistanceText}; significantTimeDiff={significantTimeDiff}", printTo=LOG_STASH_N_PLUGIN)
stash.startSpinningProcessBar()
- htmlFileData = " paths {screenshot sprite " + htmlPreviewOrStream + "} " if createHtmlReport else ""
- mergeFieldData = " code director title rating100 date studio {id} movies {movie {id} } galleries {id} performers {id} urls " if merge else ""
- DupFileSets = stash.find_duplicate_scenes(matchPhaseDistance, fragment='id tags {id name} files {path width height duration size video_codec bit_rate frame_rate} details ' + mergeFieldData + htmlFileData)
+ mergeFieldData = " code director title rating100 date studio {id name} movies {movie {id} } urls " if merge else ""
+ if not createHtmlReport:
+ htmlFileData = ""
+ DupFileSets = stash.find_duplicate_scenes(matchPhaseDistance, fragment= fragmentForSceneDetails + mergeFieldData + htmlFileData)
stash.stopSpinningProcessBar()
qtyResults = len(DupFileSets)
stash.setProgressBarIter(qtyResults)
stash.Trace("#########################################################################")
stash.Log(f"Found {qtyResults} duplicate sets...")
fileHtmlReport = None
- if createHtmlReport:
+ if not os.path.isdir(htmlReportNameFolder):
+ os.mkdir(htmlReportNameFolder)
if not os.path.isdir(htmlReportNameFolder):
- os.mkdir(htmlReportNameFolder)
- if not os.path.isdir(htmlReportNameFolder):
- stash.Error(f"Failed to create report directory {htmlReportNameFolder}.")
- return
+ stash.Error(f"Failed to create report directory {htmlReportNameFolder}.")
+ return
+ if createHtmlReport:
deleteLocalDupReportHtmlFiles(False)
fileHtmlReport = open(htmlReportName, "w")
fileHtmlReport.write(f"{getHtmlReportTableRow(qtyResults, tagDuplicates)}\n")
fileHtmlReport.write(f"{stash.Setting('htmlReportTable')}\n")
htmlReportTableHeader = stash.Setting('htmlReportTableHeader')
fileHtmlReport.write(f"{htmlReportTableRow}{htmlReportTableHeader}Scene{htmlReportTableHeader}Duplicate to Delete{htmlReportTableHeader}Scene-ToKeep{htmlReportTableHeader}Duplicate to Keep\n")
+ fileDuplicateCandidateForDeletionList = open(DuplicateCandidateForDeletionList, "w")
for DupFileSet in DupFileSets:
# stash.Trace(f"DupFileSet={DupFileSet}", toAscii=True)
@@ -819,6 +879,7 @@ def mangeDupFiles(merge=False, deleteDup=False, tagDuplicates=False, deleteBlack
elif moveToTrashCan:
sendToTrash(DupFileName)
stash.destroyScene(DupFile['id'], delete_file=True)
+ updateDuplicateCandidateForDeletionList(DupFile['id'], removeScene = True)
elif tagDuplicates or fileHtmlReport != None:
if excludeFromReportIfSignificantTimeDiff and significantTimeDiffCheck(DupFile, DupFileToKeep, True):
stash.Log(f"Skipping duplicate {DupFile['files'][0]['path']} (ID={DupFile['id']}), because of time difference greater than {significantTimeDiff} for file {DupFileToKeep['files'][0]['path']}.")
@@ -837,6 +898,7 @@ def mangeDupFiles(merge=False, deleteDup=False, tagDuplicates=False, deleteBlack
# add delete only from stash db code and button using DB delete icon
stash.Debug(f"Adding scene {DupFile['id']} to HTML report.")
writeRowToHtmlReport(fileHtmlReport, DupFile, DupFileToKeep, QtyTagForDel, tagDuplicates)
+ fileDuplicateCandidateForDeletionList.write(json.dumps(DupFile) + "\n")
if QtyTagForDelPaginate >= htmlReportPaginate:
QtyTagForDelPaginate = 0
fileHtmlReport.write("\n")
@@ -884,6 +946,7 @@ def mangeDupFiles(merge=False, deleteDup=False, tagDuplicates=False, deleteBlack
if maxDupToProcess > 0 and ((QtyTagForDel > maxDupToProcess) or (QtyTagForDel == 0 and QtyDup > maxDupToProcess)):
break
+ fileDuplicateCandidateForDeletionList.close()
if fileHtmlReport != None:
fileHtmlReport.write("\n")
if PaginateId > 0:
@@ -921,26 +984,32 @@ def findCurrentTagId(tagNames):
for tagName in tagNames:
tagId = stash.find_tags(q=tagName)
if len(tagId) > 0 and 'id' in tagId[0]:
- stash.Debug(f"Using tag name {tagName} with Tag ID {tagId[0]['id']}")
- return tagId[0]['id']
- return "-1"
+ return tagId[0]['id'], tagName
+ return "-1", None
def toJson(data):
- import json
# data = data.replace("'", '"')
data = data.replace("\\", "\\\\")
data = data.replace("\\\\\\\\", "\\\\")
return json.loads(data)
-def getAnAdvanceMenuOptionSelected(taskName, target, isBlackList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, fileNotExistToDelete, compareToLess, compareToGreater):
+def getAnAdvanceMenuOptionSelected(taskName, target, isTagOnlyScenes, isBlackList, isGrayList, isPinkList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, fileNotExistToDelete, compareToLess, compareToGreater):
stash.Log(f"Processing taskName = {taskName}, target = {target}")
if "Blacklist" in taskName:
isBlackList = True
+ if "Graylist" in taskName:
+ isGrayList = True
+ if "Pinklist" in taskName:
+ isPinkList = True
if "Less" in taskName:
compareToLess = True
if "Greater" in taskName:
compareToGreater = True
+ if ":TagOnlyScenes" in target:
+ isTagOnlyScenes = True
+ target = target.replace(":TagOnlyScenes","")
+
if "pathToDelete" in taskName:
pathToDelete = target.lower()
elif "sizeToDelete" in taskName:
@@ -961,10 +1030,15 @@ def getAnAdvanceMenuOptionSelected(taskName, target, isBlackList, pathToDelete,
pathStrToDelete = target.lower()
elif "fileNotExistToDelete" in taskName:
fileNotExistToDelete = True
- return isBlackList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, fileNotExistToDelete, compareToLess, compareToGreater
+ elif "TagOnlyScenes" in taskName:
+ isTagOnlyScenes = True
+ return isTagOnlyScenes, isBlackList, isGrayList, isPinkList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, fileNotExistToDelete, compareToLess, compareToGreater
def getAdvanceMenuOptionSelected(advanceMenuOptionSelected):
+ isTagOnlyScenes = False
isBlackList = False
+ isGrayList = False
+ isPinkList = False
pathToDelete = ""
sizeToDelete = -1
durationToDelete = -1
@@ -982,16 +1056,27 @@ def getAdvanceMenuOptionSelected(advanceMenuOptionSelected):
if "applyCombo" in stash.PLUGIN_TASK_NAME:
jsonObject = toJson(stash.JSON_INPUT['args']['Target'])
for taskName in jsonObject:
- isBlackList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, fileNotExistToDelete, compareToLess, compareToGreater = getAnAdvanceMenuOptionSelected(taskName, jsonObject[taskName], isBlackList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, compareToLess, compareToGreater)
+ isTagOnlyScenes, isBlackList, isGrayList, isPinkList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, fileNotExistToDelete, compareToLess, compareToGreater = getAnAdvanceMenuOptionSelected(taskName, jsonObject[taskName], isTagOnlyScenes, isBlackList, isGrayList, isPinkList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, fileNotExistToDelete, compareToLess, compareToGreater)
else:
- return getAnAdvanceMenuOptionSelected(stash.PLUGIN_TASK_NAME, stash.JSON_INPUT['args']['Target'], isBlackList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, compareToLess, compareToGreater)
- return isBlackList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, fileNotExistToDelete, compareToLess, compareToGreater
+ return getAnAdvanceMenuOptionSelected(stash.PLUGIN_TASK_NAME, stash.JSON_INPUT['args']['Target'], isTagOnlyScenes, isBlackList, isGrayList, isPinkList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, compareToLess, compareToGreater)
+ return isTagOnlyScenes, isBlackList, isGrayList, isPinkList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, fileNotExistToDelete, compareToLess, compareToGreater
+
+def getScenesFromReport():
+ stash.Log(f"Getting candidates for deletion from file {DuplicateCandidateForDeletionList}.")
+ scenes = []
+ lines = None
+ with open(DuplicateCandidateForDeletionList, 'r') as file:
+ lines = file.readlines()
+ for line in lines:
+ scenes += [json.loads(line)]
+ return scenes
# //////////////////////////////////////////////////////////////////////////////
# //////////////////////////////////////////////////////////////////////////////
def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=False, tagId=-1, advanceMenuOptionSelected=False):
+ tagName = None
if tagId == -1:
- tagId = findCurrentTagId([duplicateMarkForDeletion, base1_duplicateMarkForDeletion, base2_duplicateMarkForDeletion, 'DuplicateMarkForDeletion', '_DuplicateMarkForDeletion'])
+ tagId, tagName = findCurrentTagId([duplicateMarkForDeletion, base1_duplicateMarkForDeletion, base2_duplicateMarkForDeletion, 'DuplicateMarkForDeletion', '_DuplicateMarkForDeletion'])
if int(tagId) < 0:
stash.Warn(f"Could not find tag ID for tag '{duplicateMarkForDeletion}'.")
return
@@ -1000,7 +1085,7 @@ def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=F
if clearAllDupfileManagerTags:
excludedTags = [duplicateMarkForDeletion, duplicateWhitelistTag, excludeDupFileDeleteTag, graylistMarkForDeletion, longerDurationLowerResolution]
- isBlackList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, fileNotExistToDelete, compareToLess, compareToGreater = getAdvanceMenuOptionSelected(advanceMenuOptionSelected)
+ isTagOnlyScenes, isBlackList, isGrayList, isPinkList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, fileNotExistToDelete, compareToLess, compareToGreater = getAdvanceMenuOptionSelected(advanceMenuOptionSelected)
if advanceMenuOptionSelected and deleteScenes and pathToDelete == "" and tagToDelete == "" and titleToDelete == "" and pathStrToDelete == "" and sizeToDelete == -1 and durationToDelete == -1 and resolutionToDelete == -1 and ratingToDelete == -1 and fileNotExistToDelete == False:
stash.Error("Running advance menu option with no options enabled.")
return
@@ -1012,7 +1097,11 @@ def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=F
QtyFailedQuery = 0
stash.Debug("#########################################################################")
stash.startSpinningProcessBar()
- scenes = stash.find_scenes(f={"tags": {"value":tagId, "modifier":"INCLUDES"}}, fragment='id tags {id name} files {path width height duration size video_codec bit_rate frame_rate} details title rating100')
+ if isTagOnlyScenes or advanceMenuOptionSelected == False:
+ stash.Log(f"Getting candidates for deletion by using tag-ID {tagId} and tag-name {tagName}; isTagOnlyScenes={isTagOnlyScenes};advanceMenuOptionSelected={advanceMenuOptionSelected}")
+ scenes = stash.find_scenes(f={"tags": {"value":tagId, "modifier":"INCLUDES"}}, fragment='id tags {id name} files {path width height duration size video_codec bit_rate frame_rate} details title rating100')
+ else:
+ scenes = getScenesFromReport()
stash.stopSpinningProcessBar()
qtyResults = len(scenes)
stash.Log(f"Found {qtyResults} scenes with tag ({duplicateMarkForDeletion})")
@@ -1063,6 +1152,12 @@ def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=F
if isBlackList:
if not stash.startsWithInList(blacklist, scene['files'][0]['path']):
continue
+ if isGrayList:
+ if not stash.startsWithInList(graylist, scene['files'][0]['path']):
+ continue
+ if isPinkList:
+ if not stash.startsWithInList(pinklist, scene['files'][0]['path']):
+ continue
if pathToDelete != "":
if not DupFileName.lower().startswith(pathToDelete):
stash.Debug(f"Skipping file {DupFileName} because it does not start with {pathToDelete}.")
@@ -1133,7 +1228,7 @@ def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=F
if fileNotExistToDelete:
if os.path.isfile(scene['files'][0]['path']):
continue
- stash.Warn(f"Deleting duplicate '{DupFileName}'", toAscii=True, printTo=LOG_STASH_N_PLUGIN)
+ stash.Log(f"Deleting duplicate '{DupFileName}'", toAscii=True, printTo=LOG_STASH_N_PLUGIN)
if alternateTrashCanPath != "":
destPath = f"{alternateTrashCanPath }{os.sep}{DupFileNameOnly}"
if os.path.isfile(destPath):
@@ -1142,6 +1237,7 @@ def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=F
elif moveToTrashCan:
sendToTrash(DupFileName)
result = stash.destroyScene(scene['id'], delete_file=True)
+ updateDuplicateCandidateForDeletionList(scene['id'], removeScene = True)
QtyDeleted += 1
stash.Debug(f"destroyScene result={result} for file {DupFileName};QtyDeleted={QtyDeleted};Count={QtyDup} of {qtyResults}", toAscii=True)
else:
@@ -1217,6 +1313,7 @@ def mergeTags():
sys.stdout.write("{" + f"mergeTags : 'failed', id1: '{scene1}', id2: '{scene2}'" + "}")
return
stash.mergeMetadata(scene1, scene2)
+ updateScenesInReports(scene2['id'])
stash.Log(f"Done merging scenes for scene {scene1['id']} and scene {scene2['id']}")
sys.stdout.write("{" + f"mergeTags : 'complete', id1: '{scene1['id']}', id2: '{scene2['id']}'" + "}")
@@ -1277,8 +1374,33 @@ def removeAllDupTagsFromAllScenes(deleteTags=False):
else:
stash.Log(f"Clear tags {tagsToClear}")
+def updateDuplicateCandidateForDeletionList(scene, removeScene = False):
+ lines = None
+ if not os.path.isfile(DuplicateCandidateForDeletionList):
+ return
+ with open(DuplicateCandidateForDeletionList, 'r') as file:
+ lines = file.readlines()
+ if removeScene:
+ scene_id = scene
+ else:
+ scene_id = scene['id']
+ foundScene = False
+ with open(DuplicateCandidateForDeletionList, 'w') as file:
+ for line in lines:
+ if foundScene:
+ file.write(line)
+ else:
+ sceneDetails = json.loads(line)
+ if sceneDetails['id'] == scene_id:
+ if not removeScene:
+ file.write(json.dumps(scene) + "\n")
+ foundScene = True
+ else:
+ file.write(line)
+
def updateScenesInReport(fileName, scene):
stash.Log(f"Updating table rows with scene {scene} in file {fileName}")
+ results = False
scene1 = -1
scene2 = -1
strToFind = "class=\"ID_"
@@ -1286,10 +1408,12 @@ def updateScenesInReport(fileName, scene):
with open(fileName, 'r') as file:
lines = file.readlines()
stash.Log(f"line count = {len(lines)}")
+ stash.Log(f"Searching for class=\"ID_{scene}\"")
with open(fileName, 'w') as file:
for line in lines:
# stash.Debug(f"line = {line}")
if f"class=\"ID_{scene}\"" in line:
+ stash.Debug(f"Found class ID_{scene} in line: {line}")
idx = 0
while line.find(strToFind, idx) > -1:
idx = line.find(strToFind, idx) + len(strToFind)
@@ -1304,30 +1428,41 @@ def updateScenesInReport(fileName, scene):
elif scene1 != -1 and scene2 != -1:
break
if scene1 != -1 and scene2 != -1:
- sceneDetail1 = stash.find_scene(scene1)
- sceneDetail2 = stash.find_scene(scene2)
- if sceneDetail1 == None or sceneDetail2 == None:
- stash.Error("Could not get scene details for both scene1 ({scene1}) and scene2 ({scene2}); sceneDetail1={sceneDetail1}; sceneDetail2={sceneDetail2};")
+ sceneDetails1 = stash.find_scene(scene1, fragment=fragmentForSceneDetails + htmlFileData)
+ sceneDetails2 = stash.find_scene(scene2, fragment=fragmentForSceneDetails + htmlFileData)
+ if sceneDetails1 == None or sceneDetails2 == None:
+ stash.Error("Could not get scene details for both scene1 ({scene1}) and scene2 ({scene2}); sceneDetails1={sceneDetails1}; sceneDetails2={sceneDetails2};")
else:
- writeRowToHtmlReport(file, sceneDetail1, sceneDetail2)
+ stash.Log(f"Updating in report {fileName} scene {scene1} and scene {scene2}")
+ writeRowToHtmlReport(file, sceneDetails1, sceneDetails2)
+ if scene == sceneDetails1['id']:
+ results = True
+ updateDuplicateCandidateForDeletionList(sceneDetails1)
else:
stash.Error(f"Could not get both scene ID associated with scene {scene}; scene1 = {scene1}; scene2 = {scene2}")
file.write(line)
else:
file.write(line)
+ if scene1 == -1 or scene2 == -1:
+ stash.Log(f"Did not find both scene ID's associated with scene {scene}; scene1 = {scene1}; scene2 = {scene2}")
+ return results
def updateScenesInReports(scene, ReportName = htmlReportName):
if os.path.isfile(ReportName):
- updateScenesInReport(ReportName, scene)
+ if updateScenesInReport(ReportName, scene):
+ return
for x in range(2, 9999):
fileName = ReportName.replace(".html", f"_{x-1}.html")
stash.Debug(f"Checking if file '{fileName}' exist.")
if not os.path.isfile(fileName):
break
- updateScenesInReport(fileName, scene)
+ if updateScenesInReport(fileName, scene):
+ break
+ stash.Debug("updateScenesInReports complete")
else:
stash.Log(f"Report file does not exist: {ReportName}")
+deleteSceneFlagBgColor = "#646464"
def addPropertyToSceneClass(fileName, scene, property):
stash.Log(f"Inserting property {property} for scene {scene} in file {fileName}")
doStyleEndTagCheck = True
@@ -1339,14 +1474,20 @@ def addPropertyToSceneClass(fileName, scene, property):
for line in lines:
# stash.Debug(f"line = {line}")
if doStyleEndTagCheck:
- if property == "" and line.startswith(f".ID_{scene}" + "{"):
- continue
- if line.startswith(""):
- if property != "":
- styleSetting = f".ID_{scene}{property}\n"
- stash.Log(f"styleSetting = {styleSetting}")
- file.write(styleSetting)
- doStyleEndTagCheck = False
+ if scene == None:
+ if line.startswith(f".ID_") and deleteSceneFlagBgColor not in line:
+ continue
+ elif line.startswith(""):
+ doStyleEndTagCheck = False
+ else:
+ if property == "" and line.startswith(f".ID_{scene}" + "{"):
+ continue
+ if line.startswith(""):
+ if property != "":
+ styleSetting = f".ID_{scene}{property}\n"
+ stash.Log(f"styleSetting = {styleSetting}")
+ file.write(styleSetting)
+ doStyleEndTagCheck = False
file.write(line)
def addPropertyToSceneClassToAllFiles(scene, property, ReportName = htmlReportName):
@@ -1370,10 +1511,16 @@ def deleteScene(disableInReport=True, deleteFile=True):
result = None
result = stash.destroyScene(scene, delete_file=deleteFile)
if disableInReport:
- addPropertyToSceneClassToAllFiles(scene, "{background-color:gray;pointer-events:none;}")
+ addPropertyToSceneClassToAllFiles(scene, "{background-color:" + deleteSceneFlagBgColor + ";pointer-events:none;}")
+ updateDuplicateCandidateForDeletionList(scene, removeScene = True)
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}'" + "}")
+def clearAllSceneFlags():
+ addPropertyToSceneClassToAllFiles(None, None)
+ stash.Log(f"{stash.PLUGIN_TASK_NAME} complete for all scenes")
+ sys.stdout.write("{" + f"{stash.PLUGIN_TASK_NAME} : 'complete'" + "}")
+
def copyScene(moveScene=False):
scene1, scene2 = getParseData()
if scene1 == None or scene2 == None:
@@ -1384,6 +1531,7 @@ def copyScene(moveScene=False):
result = shutil.copy(scene1['files'][0]['path'], scene2['files'][0]['path'])
if moveScene:
result = stash.destroyScene(scene1['id'], delete_file=True)
+ updateDuplicateCandidateForDeletionList(scene1['id'], removeScene = True)
stash.Log(f"destroyScene for scene {scene1['id']} results = {result}")
stash.Log(f"{stash.PLUGIN_TASK_NAME} complete for scene {scene1['id']} and {scene2['id']}")
sys.stdout.write("{" + f"{stash.PLUGIN_TASK_NAME} : 'complete', id1: '{scene1['id']}', id2: '{scene2['id']}', result: '{result}'" + "}")
@@ -1482,6 +1630,9 @@ try:
elif stash.PLUGIN_TASK_NAME == "flagScene":
flagScene()
stash.Debug(f"{stash.PLUGIN_TASK_NAME} EXIT")
+ elif stash.PLUGIN_TASK_NAME == "clearAllSceneFlags":
+ clearAllSceneFlags()
+ stash.Debug(f"{stash.PLUGIN_TASK_NAME} EXIT")
elif stash.PLUGIN_TASK_NAME == "copyScene":
copyScene()
stash.Debug(f"{stash.PLUGIN_TASK_NAME} EXIT")
diff --git a/plugins/DupFileManager/DupFileManager.yml b/plugins/DupFileManager/DupFileManager.yml
index a756ebe..e128797 100644
--- a/plugins/DupFileManager/DupFileManager.yml
+++ b/plugins/DupFileManager/DupFileManager.yml
@@ -1,6 +1,6 @@
name: DupFileManager
description: Manages duplicate files.
-version: 0.2.1
+version: 0.2.2
url: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/DupFileManager
ui:
javascript:
@@ -34,6 +34,10 @@ settings:
displayName: Black List
description: Least preferential paths; Determine primary deletion candidates. E.g. C:\Downloads,C:\DelMe-3rd,C:\DelMe-2nd,C:\DeleteMeFirst
type: STRING
+ zxPinklist:
+ displayName: Pink List
+ description: An [Advance Duplicate File Deletion Menu] option for deletion using paths. E.g. C:\SomeRandomDir,E:\DelPath2
+ type: STRING
zyMaxDupToProcess:
displayName: Max Dup Process
description: (Default=0) Maximum number of duplicates to process. If 0, infinity.
diff --git a/plugins/DupFileManager/DupFileManager_report_config.py b/plugins/DupFileManager/DupFileManager_report_config.py
index 51a2cbb..2673d6c 100644
--- a/plugins/DupFileManager/DupFileManager_report_config.py
+++ b/plugins/DupFileManager/DupFileManager_report_config.py
@@ -64,8 +64,93 @@ li:hover .large {
border-radius: 4px;
box-shadow: 1px 1px 3px 3px rgba(127, 127, 127, 0.15);;
}
+/******** Dropdown buttons *********/
+.dropdown .dropdown_tag .dropdown_performer .dropdown_gallery .dropbtn {
+ font-size: 14px;
+ border: none;
+ outline: none;
+ color: white;
+ padding: 6px 10px;
+ background-color: transparent;
+ font-family: inherit; /* Important for vertical align on mobile phones */
+ margin: 0; /* Important for vertical align on mobile phones */
+}
+.dropdown-content{
+ display: none;
+ position: absolute;
+ background-color: inherit;
+ min-width: 80px;
+ box-shadow: 0px 4px 12px 0px rgba(0,0,0,0.2);
+ z-index: 1;
+}
+.dropdown-content a {
+ float: none;
+ color: black;
+ padding: 6px 10px;
+ text-decoration: none;
+ display: block;
+ text-align: left;
+}
+.dropdown:hover .dropdown-content {
+ display: block;
+}
+/*************-- Dropdown Icons --*************/
+.dropdown_icon {
+ height:22px;
+ width:30px;
+ float:left;
+}
+/*** Dropdown Tag ***/
+.dropdown_tag-content{
+ display: none;
+ position: absolute;
+ background-color: LightCoral;
+ min-width: 80px;
+ box-shadow: 0px 4px 12px 0px rgba(0,0,0,0.2);
+ z-index: 1;
+}
+.dropdown_icon:hover .dropdown_tag-content {
+ display: block;
+}
+/*** Dropdown Performer ***/
+.dropdown_performer-content{
+ display: none;
+ position: absolute;
+ background-color: LightBlue;
+ min-width: 80px;
+ box-shadow: 0px 4px 12px 0px rgba(0,0,0,0.2);
+ z-index: 1;
+}
+.dropdown_icon:hover .dropdown_performer-content {
+ display: block;
+}
+/*** Dropdown Gallery ***/
+.dropdown_gallery-content{
+ display: none;
+ position: absolute;
+ background-color: AntiqueWhite;
+ min-width: 80px;
+ box-shadow: 0px 4px 12px 0px rgba(0,0,0,0.2);
+ z-index: 1;
+}
+.dropdown_icon:hover .dropdown_gallery-content {
+ display: block;
+}
+/*** Dropdown Group ***/
+.dropdown_group-content{
+ display: none;
+ position: absolute;
+ background-color: BurlyWood;
+ min-width: 80px;
+ box-shadow: 0px 4px 12px 0px rgba(0,0,0,0.2);
+ z-index: 1;
+}
+.dropdown_icon:hover .dropdown_group-content {
+ display: block;
+}
-
+
+
+
+