From 14bb86a529d5105a292947db6ec38b0f35884333 Mon Sep 17 00:00:00 2001
From: David Maisonave <47364845+David-Maisonave@users.noreply.github.com>
Date: Fri, 13 Dec 2024 16:44:52 -0500
Subject: [PATCH] Version 1.1.0
See version history for details on all the changes.
---
plugins/DupFileManager/DupFileManager.py | 686 ++++++++++++------
plugins/DupFileManager/DupFileManager.yml | 6 +-
.../DupFileManager_report_config.py | 447 ++++++------
plugins/DupFileManager/README.md | 38 +-
plugins/DupFileManager/StashPluginHelper.py | 13 +-
plugins/DupFileManager/advance_options.html | 489 +++++++++----
plugins/DupFileManager/test.html | 51 ++
.../DupFileManager/version_history/README.md | 59 +-
plugins/FileMonitor/StashPluginHelper.py | 13 +-
plugins/RenameFile/StashPluginHelper.py | 13 +-
10 files changed, 1187 insertions(+), 628 deletions(-)
create mode 100644 plugins/DupFileManager/test.html
diff --git a/plugins/DupFileManager/DupFileManager.py b/plugins/DupFileManager/DupFileManager.py
index 778ead5..018ec8f 100644
--- a/plugins/DupFileManager/DupFileManager.py
+++ b/plugins/DupFileManager/DupFileManager.py
@@ -80,10 +80,18 @@ 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"]
+ "deleteBlackListTaggedDuplicatesLwrResOrLwrDuration", "create_duplicate_report_task", "copyScene"]
doJsonReturnModeTypes += [advanceMenuOptions]
doJsonReturn = False
-if len(sys.argv) < 2 and stash.PLUGIN_TASK_NAME in doJsonReturnModeTypes:
+def isReportOrAdvMenu():
+ if len(sys.argv) < 2:
+ if stash.PLUGIN_TASK_NAME in doJsonReturnModeTypes:
+ return True
+ if stash.PLUGIN_TASK_NAME.endswith("Flag"):
+ return True
+ return False
+
+if isReportOrAdvMenu():
doJsonReturn = True
stash.log_to_norm = stash.LogTo.FILE
elif stash.PLUGIN_TASK_NAME == "doEarlyExit":
@@ -146,10 +154,26 @@ bitRateIsImporantComp = stash.Setting('bitRateIsImporantComp')
codecIsImporantComp = stash.Setting('codecIsImporantComp')
excludeFromReportIfSignificantTimeDiff = False
+htmlReportPaginate = stash.Setting('htmlReportPaginate')
+htmlIncludeImagePreview = stash.Setting('htmlIncludeImagePreview')
+htmlIncludeVideoPreview = stash.Setting('htmlIncludeVideoPreview')
+htmlHighlightTimeDiff = stash.Setting('htmlHighlightTimeDiff')
+htmlImagePreviewSize = stash.Setting('htmlImagePreviewSize')
+htmlImagePreviewPopupSize = stash.Setting('htmlImagePreviewPopupSize')
+htmlPreviewOrStream = "stream" if stash.Setting('streamOverPreview') else "preview"
+htmlSupperHighlight = stash.Setting('htmlSupperHighlight')
+htmlDetailDiffTextColor = stash.Setting('htmlDetailDiffTextColor')
+htmlLowerHighlight = stash.Setting('htmlLowerHighlight')
+htmlReportBackgroundColor = stash.Setting('htmlReportBackgroundColor')
+htmlReportTextColor = stash.Setting('htmlReportTextColor')
+htmlVideoPreviewWidth = stash.Setting('htmlVideoPreviewWidth')
+htmlVideoPreviewHeight = stash.Setting('htmlVideoPreviewHeight')
+htmlImagePreviewPopupEnable = True
matchDupDistance = int(stash.Setting('matchDupDistance'))
matchPhaseDistance = PhashDistance.EXACT
matchPhaseDistanceText = "Exact Match"
+logTraceForAdvanceMenuOpt = False
if (stash.PLUGIN_TASK_NAME == "tag_duplicates_task" or stash.PLUGIN_TASK_NAME == "create_duplicate_report_task") and 'Target' in stash.JSON_INPUT['args']:
stash.enableProgressBar(False)
if stash.JSON_INPUT['args']['Target'].startswith("0"):
@@ -161,9 +185,40 @@ if (stash.PLUGIN_TASK_NAME == "tag_duplicates_task" or stash.PLUGIN_TASK_NAME ==
elif stash.JSON_INPUT['args']['Target'].startswith("3"):
matchDupDistance = 3
- if stash.JSON_INPUT['args']['Target'].find(":") == 1:
- significantTimeDiff = float(stash.JSON_INPUT['args']['Target'][2:])
+ stash.Trace(f"Target = {stash.JSON_INPUT['args']['Target']}")
+ targets = stash.JSON_INPUT['args']['Target'].split(":")
+ if len(targets) > 1:
+ significantTimeDiff = float(targets[1])
excludeFromReportIfSignificantTimeDiff = True
+ if len(targets) > 16:
+ if targets[2] == "true":
+ htmlIncludeImagePreview = True
+ else:
+ htmlIncludeImagePreview = False
+ htmlReportPaginate = int(targets[3])
+ htmlImagePreviewSize = int(targets[4])
+ htmlImagePreviewPopupSize = int(targets[5])
+ htmlHighlightTimeDiff = int(targets[6])
+ maxDupToProcess = int(targets[7])
+ if targets[8] == "true":
+ htmlPreviewOrStream = "stream"
+ else:
+ htmlPreviewOrStream = "preview"
+ htmlSupperHighlight = targets[9]
+ htmlDetailDiffTextColor = targets[10]
+ htmlLowerHighlight = targets[11]
+ htmlReportBackgroundColor = targets[12]
+ htmlReportTextColor = targets[13]
+ htmlVideoPreviewWidth = targets[14]
+ htmlVideoPreviewHeight = targets[15]
+ if targets[16] == "true":
+ htmlIncludeVideoPreview = True
+ else:
+ htmlIncludeVideoPreview = False
+ logTraceForAdvanceMenuOpt = True
+
+if htmlIncludeImagePreview and (htmlImagePreviewSize == htmlImagePreviewPopupSize):
+ htmlImagePreviewPopupEnable = False
if matchDupDistance == 1:
matchPhaseDistance = PhashDistance.HIGH
@@ -181,6 +236,8 @@ if significantTimeDiff > 1:
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};")
duplicateMarkForDeletion = stash.Setting('DupFileTag')
if duplicateMarkForDeletion == "":
@@ -524,12 +581,12 @@ def getHtmlReportTableRow(qtyResults, tagDuplicates):
htmlReportPrefix = htmlReportPrefix.replace('(QtyPlaceHolder)', f'{qtyResults}')
htmlReportPrefix = htmlReportPrefix.replace('(MatchTypePlaceHolder)', f'(Match Type = {matchPhaseDistanceText})')
htmlReportPrefix = htmlReportPrefix.replace('(DateCreatedPlaceHolder)', datetime.now().strftime("%d-%b-%Y, %H:%M:%S"))
+ htmlReportPrefix = htmlReportPrefix.replace("Report Info", f"Report Info - [Distance={matchDupDistance}]")
+ htmlReportPrefix = htmlReportPrefix.replace("BackgroundColorPlaceHolder", htmlReportBackgroundColor)
+ htmlReportPrefix = htmlReportPrefix.replace("TextColorPlaceHolder", htmlReportTextColor)
return htmlReportPrefix
htmlReportTableData = stash.Setting('htmlReportTableData')
-htmlDetailDiffTextColor = stash.Setting('htmlDetailDiffTextColor')
-htmlSupperHighlight = stash.Setting('htmlSupperHighlight')
-htmlLowerHighlight = stash.Setting('htmlLowerHighlight')
def getColor(Scene1, Scene2, ifScene1HigherChangeColor = False, roundUpNumber = False, qtyDiff=0):
if (Scene1 == Scene2) or (roundUpNumber and int(Scene1) == int(Scene2)):
return ""
@@ -539,6 +596,14 @@ def getColor(Scene1, Scene2, ifScene1HigherChangeColor = False, roundUpNumber =
return f' style="color:{htmlDetailDiffTextColor};background-color:{htmlLowerHighlight};"'
return f' style="color:{htmlDetailDiffTextColor};"'
+def getMarker(Scene1, Scene2, roundUpNumber = False, Marker = "*", LessThanMarker = ""):
+ if (Scene1 == Scene2) or (roundUpNumber and int(Scene1) == int(Scene2)):
+ return ""
+ if int(Scene1) > int(Scene2):
+ return Marker
+ return LessThanMarker
+
+
def getRes(Scene):
return int(Scene['files'][0]['width']) * int(Scene['files'][0]['height'])
@@ -551,8 +616,8 @@ def logReason(DupFileToKeep, Scene, reason):
stash.Debug(f"Replacing {DupFileToKeep['files'][0]['path']} with {Scene['files'][0]['path']} for candidate to keep. Reason={reason}")
-def getSceneID(scene):
- return htmlReportTableData.replace("
Res Durration BitRate Codec FrameRate size ID index ")
- fileHtmlReport.write(f"{DupFile['files'][0]['width']}x{DupFile['files'][0]['height']} {DupFile['files'][0]['duration']} {DupFile['files'][0]['bit_rate']} {DupFile['files'][0]['video_codec']} {DupFile['files'][0]['frame_rate']} {DupFile['files'][0]['size']} {DupFile['id']} {QtyTagForDel} ")
+ fileHtmlReport.write(f"
{getMarker(getRes(DupFile), getRes(DupFileToKeep))}Res {getMarker(DupFile['files'][0]['duration'], DupFileToKeep['files'][0]['duration'], True)}Durration BitRate Codec FrameRate size ID index ")
+ fileHtmlReport.write(f"{DupFile['files'][0]['width']}x{DupFile['files'][0]['height']} {DupFile['files'][0]['duration']} {DupFile['files'][0]['bit_rate']} {DupFile['files'][0]['video_codec']} {DupFile['files'][0]['frame_rate']} {DupFile['files'][0]['size']} {DupFile['id']} {itemIndex} ")
+ if doTraceDetails:
+ stash.Trace(f"Adding html report details for scene {DupFile['id']} / {DupFileToKeep['id']}; Duration {DupFile['files'][0]['duration']} / {DupFileToKeep['files'][0]['duration']}; Size {DupFile['files'][0]['size']} / {DupFileToKeep['files'][0]['size']}; bit_rate {DupFile['files'][0]['bit_rate']} / {DupFileToKeep['files'][0]['bit_rate']}; path {DupFile['files'][0]['path']} / {DupFileToKeep['files'][0]['path']}")
if DupFile['id'] in reasonDict:
fileHtmlReport.write(f"Reason: {reasonDict[DupFile['id']]} ")
@@ -642,161 +716,222 @@ def writeRowToHtmlReport(fileHtmlReport, DupFile, DupFileToKeep, QtyTagForDel =
fileHtmlReport.write(f"Reason: not ExcludeTag vs ExcludeTag ")
fileHtmlReport.write("
")
- fileHtmlReport.write('File Options ')
- fileHtmlReport.write(f"
Delete
")
- fileHtmlReport.write(f"
Remove Scene
")
- fileHtmlReport.write(f"
Copy to [Duplicate to Keep]
")
- fileHtmlReport.write(f"
Move to [Duplicate to Keep] and Metadata
")
- fileHtmlReport.write(f"
Copy this Name to [Duplicate to Keep]
")
- fileHtmlReport.write("
")
-
- fileHtmlReport.write(f"Flag or Tag ")
- fileHtmlReport.write(f"
Flag this scene
")
- # ToDo: Add following buttons:
- # rename file
- if dupFileExist and tagDuplicates:
- fileHtmlReport.write(f"
Remove Duplicate Tag
")
- fileHtmlReport.write(f"
Add Exclude Tag
")
- fileHtmlReport.write(f"
Merge Tags, Performers, & Galleries
")
- fileHtmlReport.write(f"
Flag Yellow
")
- fileHtmlReport.write(f"
Flag Green
")
- fileHtmlReport.write(f"
Flag Orange
")
- fileHtmlReport.write(f"
Flag Cyan
")
- fileHtmlReport.write(f"
Flag Pink
")
- fileHtmlReport.write(f"
Flag Red
")
- fileHtmlReport.write(f"
Flag Strike-through
")
- fileHtmlReport.write(f"
Flag Disable-scene
")
- fileHtmlReport.write(f"
Remove All Flags
")
- fileHtmlReport.write("
")
-
-
- if dupFileExist:
- fileHtmlReport.write('Local File ')
- fileHtmlReport.write(f"
")
- fileHtmlReport.write(f"
")
- fileHtmlReport.write("
")
- else:
- fileHtmlReport.write(fileDoesNotExistStr)
DupToKeepMissingTag, DelCandidateMissingTag = doesDelCandidateHaveMetadataNotInDupToKeep(DupFile, DupFileToKeep, 'tags')
+ DupToKeepMissingPerformer, DelCandidateMissingPerformer = doesDelCandidateHaveMetadataNotInDupToKeep(DupFile, DupFileToKeep, 'performers')
+ DupToKeepMissingGallery, DelCandidateMissingGallery = doesDelCandidateHaveMetadataNotInDupToKeep(DupFile, DupFileToKeep, 'galleries', 'title')
+ DupToKeepMissingGroup, DelCandidateMissingGroup = doesDelCandidateHaveMetadataNotInDupToKeep(DupFile, DupFileToKeep, 'groups')
+
+ QtyIconsOnToolBar = 2
+ MaxQtyIconsOnToolBar = 7
+ fileHtmlReport.write(f"")
+ fileHtmlReport.write(f"")
+ fileHtmlReport.write(f"")
if len(DupFile['tags']) > 0:
+ QtyIconsOnToolBar += 1
+ menuitem = f""
if DupToKeepMissingTag:
- fileHtmlReport.write(htmlTagPrefix.replace(defaultColorTag, "YellowTag.png"))
- else:
- fileHtmlReport.write(htmlTagPrefix)
+ menuitem = menuitem.replace("icon-blue-tag", "icon-yellow-tag")
+ fileHtmlReport.write(menuitem)
+ if len(DupFile['performers']) > 0:
+ QtyIconsOnToolBar += 1
+ menuitem = f""
+ if DupToKeepMissingPerformer:
+ menuitem = menuitem.replace("icon-headshot", "icon-yellow-headshot")
+ fileHtmlReport.write(menuitem)
+ if len(DupFile['galleries']) > 0:
+ QtyIconsOnToolBar += 1
+ menuitem = f""
+ if DupToKeepMissingGallery:
+ menuitem = menuitem.replace("icon-galleries", "icon-yellow-galleries")
+ fileHtmlReport.write(menuitem)
+ if len(DupFile['groups']) > 0:
+ QtyIconsOnToolBar += 1
+ menuitem = f""
+ if DupToKeepMissingGroup:
+ menuitem = menuitem.replace("icon-group", "icon-yellow-group")
+ fileHtmlReport.write(menuitem)
+ fileHtmlReport.write(f"
")
+ fileHtmlReport.write(f"
")
+ if QtyIconsOnToolBar > 5:
+ MaxQtyIconsOnToolBar = 6
+ elif QtyIconsOnToolBar < 4:
+ MaxQtyIconsOnToolBar = 8
+ if QtyIconsOnToolBar < MaxQtyIconsOnToolBar:
+ QtyIconsOnToolBar += 1
+ fileHtmlReport.write(f"
")
+ if QtyIconsOnToolBar < MaxQtyIconsOnToolBar:
+ QtyIconsOnToolBar += 1
+ fileHtmlReport.write(f"
")
+ if QtyIconsOnToolBar < MaxQtyIconsOnToolBar:
+ QtyIconsOnToolBar += 1
+ fileHtmlReport.write(f"
")
+ if QtyIconsOnToolBar < MaxQtyIconsOnToolBar:
+ QtyIconsOnToolBar += 1
+ fileHtmlReport.write(f"
")
+ if QtyIconsOnToolBar < MaxQtyIconsOnToolBar:
+ QtyIconsOnToolBar += 1
+ fileHtmlReport.write(f"
")
+ fileHtmlReport.write("
")
+ fileHtmlReport.write(f"")
+ fileHtmlReport.write(f"
Delete
")
+ fileHtmlReport.write(f"
Remove Scene
")
+ fileHtmlReport.write('')
+ fileHtmlReport.write(f"
Copy to [Duplicate to Keep]
")
+ fileHtmlReport.write(f"
Move to [Duplicate to Keep] and Metadata
")
+ fileHtmlReport.write('')
+ fileHtmlReport.write(f"
Copy this Name to [Duplicate to Keep]
")
+ if dupFileExist:
+ fileHtmlReport.write('')
+ fileHtmlReport.write(f"
")
+ fileHtmlReport.write(f"
")
+ fileHtmlReport.write("
")
+ fileHtmlReport.write(f"")
+ if dupFileExist and tagDuplicates:
+ fileHtmlReport.write(f"
Remove Duplicate Tag
")
+ fileHtmlReport.write(f"
Add Exclude Tag
")
+ fileHtmlReport.write(f"
Merge Tags, Performers, & Galleries
")
+ fileHtmlReport.write('')
+ fileHtmlReport.write(f"
Flag this scene
")
+ fileHtmlReport.write(f"
Flag Cyan
")
+ fileHtmlReport.write(f"
Flag Green
")
+ fileHtmlReport.write(f"
Flag Orange
")
+ fileHtmlReport.write(f"
Flag Yellow
")
+ fileHtmlReport.write(f"
Flag Pink
")
+ fileHtmlReport.write(f"
Flag Red
")
+ fileHtmlReport.write('')
+ fileHtmlReport.write(f"
Flag Strike-through
")
+ fileHtmlReport.write(f"
Flag Disable-scene
")
+ fileHtmlReport.write('')
+ fileHtmlReport.write(f"
Erase All Flags
")
+ fileHtmlReport.write("
")
+ if len(DupFile['tags']) > 0:
+ fileHtmlReport.write(f"")
for tag in DupFile['tags']:
# if not tag['ignore_auto_tag']:
- fileHtmlReport.write(f"
{tag['name']}
")
- fileHtmlReport.write("
")
- DupToKeepMissingPerformer, DelCandidateMissingPerformer = doesDelCandidateHaveMetadataNotInDupToKeep(DupFile, DupFileToKeep, 'performers')
+ fileHtmlReport.write(f"{tag['name']}
")
+ fileHtmlReport.write("")
if len(DupFile['performers']) > 0:
- if DupToKeepMissingPerformer:
- fileHtmlReport.write(htmlPerformerPrefix.replace(defaultColorPerformer, "YellowHeadshot.png"))
- else:
- fileHtmlReport.write(htmlPerformerPrefix)
+ fileHtmlReport.write(f"")
for performer in DupFile['performers']:
- fileHtmlReport.write(f"
{performer['name']}
")
- fileHtmlReport.write("
")
- DupToKeepMissingGallery, DelCandidateMissingGallery = doesDelCandidateHaveMetadataNotInDupToKeep(DupFile, DupFileToKeep, 'galleries', 'title')
+ fileHtmlReport.write(f"{performer['name']}
")
+ fileHtmlReport.write("")
if len(DupFile['galleries']) > 0:
- if DupToKeepMissingGallery:
- fileHtmlReport.write(htmlGalleryPrefix.replace(defaultColorGalleries, "YellowGalleries.png"))
- else:
- fileHtmlReport.write(htmlGalleryPrefix)
+ fileHtmlReport.write(f"")
for gallery in DupFile['galleries']:
gallery = stash.getGalleryName(gallery['id'])
- fileHtmlReport.write(f"
{gallery['title']}
")
- fileHtmlReport.write("
")
- DupToKeepMissingGroup, DelCandidateMissingGroup = doesDelCandidateHaveMetadataNotInDupToKeep(DupFile, DupFileToKeep, 'groups')
+ fileHtmlReport.write(f"{gallery['title']}
")
+ fileHtmlReport.write("")
if len(DupFile['groups']) > 0:
- if DupToKeepMissingGroup:
- fileHtmlReport.write(htmlGroupPrefix.replace(defaultColorGroup, "YellowGroup.png"))
- else:
- fileHtmlReport.write(htmlGroupPrefix)
+ fileHtmlReport.write(f"")
for group in DupFile['groups']:
- fileHtmlReport.write(f"
{group['group']['name']}
")
- fileHtmlReport.write("
")
-
+ fileHtmlReport.write(f"{group['group']['name']}
")
+ fileHtmlReport.write("")
+ if not dupFileExist:
+ fileHtmlReport.write(fileDoesNotExistStr)
fileHtmlReport.write("")
+ # ///////////////////////////////
videoPreview = f" "
if htmlIncludeImagePreview:
- imagePreview = f""
- fileHtmlReport.write(f"{getSceneID(DupFileToKeep)}{videoPreview} {imagePreview}
")
- else:
+ spanPreviewImage = ""
+ if htmlImagePreviewPopupEnable:
+ spanPreviewImage = f" "
+ imagePreview = f" {spanPreviewImage} "
+ if htmlIncludeVideoPreview:
+ fileHtmlReport.write(f"{getSceneID(DupFileToKeep)}{videoPreview} {imagePreview}
")
+ else:
+ fileHtmlReport.write(f"{getSceneID(DupFileToKeep)}{imagePreview}")
+ elif htmlIncludeVideoPreview:
fileHtmlReport.write(f"{getSceneID(DupFileToKeep)}{videoPreview}")
fileHtmlReport.write(f"{getSceneID(DupFileToKeep)}{getPath(DupFileToKeep)} ")
fileHtmlReport.write(f"
Res Durration BitRate Codec FrameRate size ID ")
fileHtmlReport.write(f"{DupFileToKeep['files'][0]['width']}x{DupFileToKeep['files'][0]['height']} {DupFileToKeep['files'][0]['duration']} {DupFileToKeep['files'][0]['bit_rate']} {DupFileToKeep['files'][0]['video_codec']} {DupFileToKeep['files'][0]['frame_rate']} {DupFileToKeep['files'][0]['size']} {DupFileToKeep['id']}
")
- fileHtmlReport.write('File Options ')
- fileHtmlReport.write(f"
Delete
")
- fileHtmlReport.write(f"
Remove
")
- fileHtmlReport.write(f"
Rename
")
- fileHtmlReport.write("
")
+ fileHtmlReport.write(f"")
+ fileHtmlReport.write(f"")
+ fileHtmlReport.write(f"")
+ if len(DupFileToKeep['tags']) > 0:
+ QtyIconsOnToolBar += 1
+ menuitem = f""
+ if DelCandidateMissingTag:
+ menuitem = menuitem.replace("icon-blue-tag", "icon-pink-tag")
+ fileHtmlReport.write(menuitem)
+ if len(DupFileToKeep['performers']) > 0:
+ QtyIconsOnToolBar += 1
+ menuitem = f""
+ if DelCandidateMissingPerformer:
+ menuitem = menuitem.replace("icon-headshot", "icon-pink-headshot")
+ fileHtmlReport.write(menuitem)
+ if len(DupFileToKeep['galleries']) > 0:
+ QtyIconsOnToolBar += 1
+ menuitem = f""
+ if DelCandidateMissingGallery:
+ menuitem = menuitem.replace("icon-galleries", "icon-pink-galleries")
+ fileHtmlReport.write(menuitem)
+ if len(DupFileToKeep['groups']) > 0:
+ QtyIconsOnToolBar += 1
+ menuitem = f""
+ if DelCandidateMissingGroup:
+ menuitem = menuitem.replace("icon-group", "icon-pink-group")
+ fileHtmlReport.write(menuitem)
+ fileHtmlReport.write("
")
- fileHtmlReport.write(f"Flag or Tag ")
- if isTaggedExcluded(DupFileToKeep):
- fileHtmlReport.write(f"
Remove Exclude Tag
")
- fileHtmlReport.write(f"
Flag this scene
")
- fileHtmlReport.write(f"
Flag Yellow
")
- fileHtmlReport.write(f"
Flag Green
")
- fileHtmlReport.write(f"
Flag Orange
")
- fileHtmlReport.write(f"
Flag Cyan
")
- fileHtmlReport.write(f"
Flag Pink
")
- fileHtmlReport.write(f"
Flag Red
")
- fileHtmlReport.write(f"
Flag Strike-through
")
- fileHtmlReport.write(f"
Flag Disable-scene
")
- fileHtmlReport.write(f"
Remove All Flags
")
- fileHtmlReport.write("
")
-
-
- fileHtmlReport.write('Local File ')
- fileHtmlReport.write(f"
")
+ fileHtmlReport.write(f"
")
+ fileHtmlReport.write(f"
Delete
")
+ fileHtmlReport.write(f"
Remove
")
+ fileHtmlReport.write(f"
Rename
")
+ fileHtmlReport.write('')
+ fileHtmlReport.write(f"
")
if toKeepFileExist:
- fileHtmlReport.write(f"
")
- fileHtmlReport.write("
")
- if not toKeepFileExist:
- fileHtmlReport.write(fileDoesNotExistStr)
+ fileHtmlReport.write(f"
")
+ fileHtmlReport.write("
")
+
+ fileHtmlReport.write(f"")
+ if isTaggedExcluded(DupFileToKeep):
+ fileHtmlReport.write(f"
Remove Exclude Tag
")
+ fileHtmlReport.write('')
+ fileHtmlReport.write(f"
Flag this scene
")
+ fileHtmlReport.write(f"
Flag Cyan
")
+ fileHtmlReport.write(f"
Flag Green
")
+ fileHtmlReport.write(f"
Flag Orange
")
+ fileHtmlReport.write(f"
Flag Yellow
")
+ fileHtmlReport.write(f"
Flag Pink
")
+ fileHtmlReport.write(f"
Flag Red
")
+ fileHtmlReport.write('')
+ fileHtmlReport.write(f"
Flag Strike-through
")
+ fileHtmlReport.write(f"
Flag Disable-scene
")
+ fileHtmlReport.write('')
+ fileHtmlReport.write(f"
Remove All Flags
")
+ fileHtmlReport.write("
")
if len(DupFileToKeep['tags']) > 0:
- if DelCandidateMissingTag:
- fileHtmlReport.write(htmlTagPrefix.replace(defaultColorTag, "RedTag.png"))
- else:
- fileHtmlReport.write(htmlTagPrefix)
+ fileHtmlReport.write(f"")
for tag in DupFileToKeep['tags']:
# if not tag['ignore_auto_tag']:
- fileHtmlReport.write(f"
{tag['name']}
")
- fileHtmlReport.write("
")
+ fileHtmlReport.write(f"{tag['name']}
")
+ fileHtmlReport.write("")
if len(DupFileToKeep['performers']) > 0:
- if DelCandidateMissingPerformer:
- fileHtmlReport.write(htmlPerformerPrefix.replace(defaultColorPerformer, "PinkHeadshot.png"))
- else:
- fileHtmlReport.write(htmlPerformerPrefix)
+ fileHtmlReport.write(f"")
for performer in DupFileToKeep['performers']:
- fileHtmlReport.write(f"
{performer['name']}
")
- fileHtmlReport.write("
")
+ fileHtmlReport.write(f"{performer['name']}
")
+ fileHtmlReport.write("")
if len(DupFileToKeep['galleries']) > 0:
- if DelCandidateMissingGallery:
- fileHtmlReport.write(htmlGalleryPrefix.replace(defaultColorGalleries, "PinkGalleries.png"))
- else:
- fileHtmlReport.write(htmlGalleryPrefix)
+ fileHtmlReport.write(f"")
for gallery in DupFileToKeep['galleries']:
gallery = stash.getGalleryName(gallery['id'])
- fileHtmlReport.write(f"
{gallery['title']}
")
- fileHtmlReport.write("
")
+ fileHtmlReport.write(f"{gallery['title']}
")
+ fileHtmlReport.write("")
if len(DupFileToKeep['groups']) > 0:
- if DelCandidateMissingGroup:
- fileHtmlReport.write(htmlGroupPrefix.replace(defaultColorGroup, "PinkGroup.png"))
- else:
- fileHtmlReport.write(htmlGroupPrefix)
+ fileHtmlReport.write(f"")
for group in DupFileToKeep['groups']:
- fileHtmlReport.write(f"
{group['group']['name']}
")
- fileHtmlReport.write("
")
- # ToDo: Add following buttons:
- # rename file
+ fileHtmlReport.write(f"{group['group']['name']}
")
+ fileHtmlReport.write("")
+
+ if not toKeepFileExist:
+ fileHtmlReport.write(fileDoesNotExistStr)
fileHtmlReport.write(f"")
- fileHtmlReport.write(f"\n")
+ fileHtmlReport.write(f"{ToDeleteSceneIDSrchStr}{DupFile['id']}{ToKeepSceneIDSrchStr}{DupFileToKeep['id']}{itemIndexSrchStr}{itemIndex}:: -->\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 + "} "
@@ -804,6 +939,8 @@ mergeFieldData = " code director title rating100 date studio {id name} urls "
fragmentForSceneDetails += mergeFieldData + htmlFileData
DuplicateCandidateForDeletionList = f"{htmlReportNameFolder}{os.sep}DuplicateCandidateForDeletionList.txt"
+# //////////////////////////////////////////////////////////////////////////////
+# //////////////////////////////////////////////////////////////////////////////
def mangeDupFiles(merge=False, deleteDup=False, tagDuplicates=False, deleteBlacklistOnly=False, deleteLowerResAndDuration=False):
global reasonDict
global htmlFileData
@@ -813,7 +950,6 @@ def mangeDupFiles(merge=False, deleteDup=False, tagDuplicates=False, deleteBlack
stash.Trace(f"dupTagId={dupTagId} name={duplicateMarkForDeletion}")
createHtmlReport = stash.Setting('createHtmlReport')
htmlReportNameHomePage = htmlReportName
- htmlReportPaginate = stash.Setting('htmlReportPaginate')
addDupWhitelistTag()
@@ -855,9 +991,14 @@ def mangeDupFiles(merge=False, deleteDup=False, tagDuplicates=False, deleteBlack
deleteLocalDupReportHtmlFiles(False)
fileHtmlReport = open(htmlReportName, "w")
fileHtmlReport.write(f"{getHtmlReportTableRow(qtyResults, tagDuplicates)}\n")
+ fileHtmlReport.write("Next ")
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")
+ SceneTableHeader = htmlReportTableHeader
+ if htmlIncludeVideoPreview or htmlIncludeImagePreview:
+ fileHtmlReport.write(f"{htmlReportTableRow}{SceneTableHeader}Scene{htmlReportTableHeader}Duplicate to Delete{SceneTableHeader}Scene-ToKeep{htmlReportTableHeader}Duplicate to Keep\n")
+ else:
+ fileHtmlReport.write(f"{htmlReportTableRow}{htmlReportTableHeader}Duplicate to Delete{htmlReportTableHeader}Duplicate to Keep\n")
fileDuplicateCandidateForDeletionList = open(DuplicateCandidateForDeletionList, "w")
for DupFileSet in DupFileSets:
@@ -1009,20 +1150,21 @@ 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)
+ DupFile['DupFileToKeep'] = DupFileToKeep['id']
fileDuplicateCandidateForDeletionList.write(json.dumps(DupFile) + "\n")
if QtyTagForDelPaginate >= htmlReportPaginate:
QtyTagForDelPaginate = 0
fileHtmlReport.write("
\n")
- homeHtmReportLink = f"