Added advance multiple options

This commit is contained in:
David Maisonave
2024-11-04 04:22:50 -05:00
parent 6862a8496c
commit 579c7c5b72
4 changed files with 1738 additions and 1584 deletions

View File

@@ -3,8 +3,13 @@
# Get the latest developers version from following link: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/DupFileManager # Get the latest developers version from following link: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/DupFileManager
# Note: To call this script outside of Stash, pass argument --url # Note: To call this script outside of Stash, pass argument --url
# Example: python DupFileManager.py --url http://localhost:9999 -a # Example: python DupFileManager.py --url http://localhost:9999 -a
import ModulesValidate try:
ModulesValidate.modulesInstalled(["send2trash", "requests"], silent=True) import ModulesValidate
ModulesValidate.modulesInstalled(["send2trash", "requests"], silent=True)
except Exception as e:
import traceback, sys
tb = traceback.format_exc()
print(f"ModulesValidate Exception. Error: {e}\nTraceBack={tb}", file=sys.stderr)
import os, sys, time, pathlib, argparse, platform, shutil, traceback, logging, requests import os, sys, time, pathlib, argparse, platform, shutil, traceback, logging, requests
from datetime import datetime from datetime import datetime
from StashPluginHelper import StashPluginHelper from StashPluginHelper import StashPluginHelper
@@ -60,7 +65,7 @@ stash = StashPluginHelper(
) )
stash.convertToAscii = True stash.convertToAscii = True
advanceMenuOptions = [ "pathToDelete", "pathToDeleteBlacklist", "sizeToDeleteLess", "sizeToDeleteGreater", "sizeToDeleteBlacklistLess", "sizeToDeleteBlacklistGreater", "durationToDeleteLess", "durationToDeleteGreater", "durationToDeleteBlacklistLess", "durationToDeleteBlacklistGreater", advanceMenuOptions = [ "applyCombo", "applyComboBlacklist", "pathToDelete", "pathToDeleteBlacklist", "sizeToDeleteLess", "sizeToDeleteGreater", "sizeToDeleteBlacklistLess", "sizeToDeleteBlacklistGreater", "durationToDeleteLess", "durationToDeleteGreater", "durationToDeleteBlacklistLess", "durationToDeleteBlacklistGreater",
"commonResToDeleteLess", "commonResToDeleteEq", "commonResToDeleteGreater", "commonResToDeleteBlacklistLess", "commonResToDeleteBlacklistEq", "commonResToDeleteBlacklistGreater", "resolutionToDeleteLess", "resolutionToDeleteEq", "resolutionToDeleteGreater", "commonResToDeleteLess", "commonResToDeleteEq", "commonResToDeleteGreater", "commonResToDeleteBlacklistLess", "commonResToDeleteBlacklistEq", "commonResToDeleteBlacklistGreater", "resolutionToDeleteLess", "resolutionToDeleteEq", "resolutionToDeleteGreater",
"resolutionToDeleteBlacklistLess", "resolutionToDeleteBlacklistEq", "resolutionToDeleteBlacklistGreater", "ratingToDeleteLess", "ratingToDeleteEq", "ratingToDeleteGreater", "ratingToDeleteBlacklistLess", "ratingToDeleteBlacklistEq", "ratingToDeleteBlacklistGreater", "resolutionToDeleteBlacklistLess", "resolutionToDeleteBlacklistEq", "resolutionToDeleteBlacklistGreater", "ratingToDeleteLess", "ratingToDeleteEq", "ratingToDeleteGreater", "ratingToDeleteBlacklistLess", "ratingToDeleteBlacklistEq", "ratingToDeleteBlacklistGreater",
"tagToDelete", "tagToDeleteBlacklist", "titleToDelete", "titleToDeleteBlacklist", "pathStrToDelete", "pathStrToDeleteBlacklist"] "tagToDelete", "tagToDeleteBlacklist", "titleToDelete", "titleToDeleteBlacklist", "pathStrToDelete", "pathStrToDeleteBlacklist"]
@@ -503,7 +508,7 @@ def isWorseKeepCandidate(DupFileToKeep, Scene):
def killScanningJobs(): def killScanningJobs():
try: try:
if killScanningPostProcess: if killScanningPostProcess:
stash.stopJobs(0, "Scanning...") stash.stopJobs(1, "Scanning...")
except Exception as e: except Exception as e:
tb = traceback.format_exc() tb = traceback.format_exc()
stash.Error(f"Exception while trying to kill scan jobs; Error: {e}\nTraceBack={tb}") stash.Error(f"Exception while trying to kill scan jobs; Error: {e}\nTraceBack={tb}")
@@ -914,7 +919,45 @@ def findCurrentTagId(tagNames):
return tagId[0]['id'] return tagId[0]['id']
return "-1" return "-1"
def getAdvanceMenuOptionSelected(): 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):
stash.Log(f"Processing taskName = {taskName}, target = {target}")
if "Blacklist" in taskName:
isBlackList = True
if "Less" in taskName:
compareToLess = True
if "Greater" in taskName:
compareToGreater = True
if "pathToDelete" in taskName:
pathToDelete = target.lower()
elif "sizeToDelete" in taskName:
sizeToDelete = int(target)
elif "durationToDelete" in taskName:
durationToDelete = int(target)
elif "commonResToDelete" in taskName:
resolutionToDelete = int(target)
elif "resolutionToDelete" in taskName:
resolutionToDelete = int(target)
elif "ratingToDelete" in taskName:
ratingToDelete = int(target) * 20
elif "tagToDelete" in taskName:
tagToDelete = target.lower()
elif "titleToDelete" in taskName:
titleToDelete = target.lower()
elif "pathStrToDelete" in taskName:
pathStrToDelete = target.lower()
elif "fileNotExistToDelete" in taskName:
fileNotExistToDelete = True
return isBlackList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, fileNotExistToDelete, compareToLess, compareToGreater
def getAdvanceMenuOptionSelected(advanceMenuOptionSelected):
isBlackList = False isBlackList = False
pathToDelete = "" pathToDelete = ""
sizeToDelete = -1 sizeToDelete = -1
@@ -924,35 +967,18 @@ def getAdvanceMenuOptionSelected():
tagToDelete = "" tagToDelete = ""
titleToDelete = "" titleToDelete = ""
pathStrToDelete = "" pathStrToDelete = ""
fileNotExistToDelete = False
compareToLess = False compareToLess = False
compareToGreater = False compareToGreater = False
if advanceMenuOptionSelected:
if 'Target' in stash.JSON_INPUT['args']: if 'Target' in stash.JSON_INPUT['args']:
if "Blacklist" in stash.PLUGIN_TASK_NAME: if "applyCombo" in stash.PLUGIN_TASK_NAME:
isBlackList = True jsonObject = toJson(stash.JSON_INPUT['args']['Target'])
if "Less" in stash.PLUGIN_TASK_NAME: for taskName in jsonObject:
compareToLess = True 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)
if "Greater" in stash.PLUGIN_TASK_NAME: else:
compareToGreater = True 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
if "pathToDelete" in stash.PLUGIN_TASK_NAME:
pathToDelete = stash.JSON_INPUT['args']['Target'].lower()
elif "sizeToDelete" in stash.PLUGIN_TASK_NAME:
sizeToDelete = int(stash.JSON_INPUT['args']['Target'])
elif "durationToDelete" in stash.PLUGIN_TASK_NAME:
durationToDelete = int(stash.JSON_INPUT['args']['Target'])
elif "commonResToDelete" in stash.PLUGIN_TASK_NAME:
resolutionToDelete = int(stash.JSON_INPUT['args']['Target'])
elif "resolutionToDelete" in stash.PLUGIN_TASK_NAME:
resolutionToDelete = int(stash.JSON_INPUT['args']['Target'])
elif "ratingToDelete" in stash.PLUGIN_TASK_NAME:
ratingToDelete = int(stash.JSON_INPUT['args']['Target']) * 20
elif "tagToDelete" in stash.PLUGIN_TASK_NAME:
tagToDelete = stash.JSON_INPUT['args']['Target'].lower()
elif "titleToDelete" in stash.PLUGIN_TASK_NAME:
titleToDelete = stash.JSON_INPUT['args']['Target'].lower()
elif "pathStrToDelete" in stash.PLUGIN_TASK_NAME:
pathStrToDelete = stash.JSON_INPUT['args']['Target'].lower()
return isBlackList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, compareToLess, compareToGreater
def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=False, tagId=-1, advanceMenuOptionSelected=False): def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=False, tagId=-1, advanceMenuOptionSelected=False):
if tagId == -1: if tagId == -1:
@@ -965,19 +991,10 @@ def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=F
if clearAllDupfileManagerTags: if clearAllDupfileManagerTags:
excludedTags = [duplicateMarkForDeletion, duplicateWhitelistTag, excludeDupFileDeleteTag, graylistMarkForDeletion, longerDurationLowerResolution] excludedTags = [duplicateMarkForDeletion, duplicateWhitelistTag, excludeDupFileDeleteTag, graylistMarkForDeletion, longerDurationLowerResolution]
isBlackList = False isBlackList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, fileNotExistToDelete, compareToLess, compareToGreater = getAdvanceMenuOptionSelected(advanceMenuOptionSelected)
pathToDelete = "" 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:
sizeToDelete = -1 stash.Error("Running advance menu option with no options enabled.")
durationToDelete = -1 return
resolutionToDelete = -1
ratingToDelete = -1
tagToDelete = ""
titleToDelete = ""
pathStrToDelete = ""
compareToLess = False
compareToGreater = False
if advanceMenuOptionSelected:
isBlackList, pathToDelete, sizeToDelete, durationToDelete, resolutionToDelete, ratingToDelete, tagToDelete, titleToDelete, pathStrToDelete, compareToLess, compareToGreater = getAdvanceMenuOptionSelected()
QtyDup = 0 QtyDup = 0
QtyDeleted = 0 QtyDeleted = 0
@@ -1037,16 +1054,15 @@ def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=F
if isBlackList: if isBlackList:
if not stash.startsWithInList(blacklist, scene['files'][0]['path']): if not stash.startsWithInList(blacklist, scene['files'][0]['path']):
continue continue
if pathToDelete != "": if pathToDelete != "":
if not DupFileName.lower().startswith(pathToDelete): if not DupFileName.lower().startswith(pathToDelete):
stash.Debug(f"Skipping file {DupFileName} because it does not start with {pathToDelete}.") stash.Debug(f"Skipping file {DupFileName} because it does not start with {pathToDelete}.")
continue continue
elif pathStrToDelete != "": if pathStrToDelete != "":
if not pathStrToDelete in DupFileName.lower(): if not pathStrToDelete in DupFileName.lower():
stash.Debug(f"Skipping file {DupFileName} because it does not contain value {pathStrToDelete}.") stash.Debug(f"Skipping file {DupFileName} because it does not contain value {pathStrToDelete}.")
continue continue
elif sizeToDelete != -1: if sizeToDelete != -1:
compareTo = int(scene['files'][0]['size']) compareTo = int(scene['files'][0]['size'])
if compareToLess: if compareToLess:
if not (compareTo < sizeToDelete): if not (compareTo < sizeToDelete):
@@ -1057,7 +1073,7 @@ def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=F
else: else:
if not compareTo == sizeToDelete: if not compareTo == sizeToDelete:
continue continue
elif durationToDelete != -1: if durationToDelete != -1:
compareTo = int(scene['files'][0]['duration']) compareTo = int(scene['files'][0]['duration'])
if compareToLess: if compareToLess:
if not (compareTo < durationToDelete): if not (compareTo < durationToDelete):
@@ -1068,7 +1084,7 @@ def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=F
else: else:
if not compareTo == durationToDelete: if not compareTo == durationToDelete:
continue continue
elif resolutionToDelete != -1: if resolutionToDelete != -1:
compareTo = int(scene['files'][0]['width']) * int(scene['files'][0]['height']) compareTo = int(scene['files'][0]['width']) * int(scene['files'][0]['height'])
if compareToLess: if compareToLess:
if not (compareTo < resolutionToDelete): if not (compareTo < resolutionToDelete):
@@ -1079,7 +1095,7 @@ def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=F
else: else:
if not compareTo == resolutionToDelete: if not compareTo == resolutionToDelete:
continue continue
elif ratingToDelete != -1: if ratingToDelete != -1:
if scene['rating100'] == "None": if scene['rating100'] == "None":
compareTo = 0 compareTo = 0
else: else:
@@ -1093,11 +1109,11 @@ def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=F
else: else:
if not compareTo == resolutionToDelete: if not compareTo == resolutionToDelete:
continue continue
elif titleToDelete != "": if titleToDelete != "":
if not titleToDelete in scene['title'].lower(): if not titleToDelete in scene['title'].lower():
stash.Debug(f"Skipping file {DupFileName} because it does not contain value {titleToDelete} in title ({scene['title']}).") stash.Debug(f"Skipping file {DupFileName} because it does not contain value {titleToDelete} in title ({scene['title']}).")
continue continue
elif tagToDelete != "": if tagToDelete != "":
doProcessThis = False doProcessThis = False
for tag in scene['tags']: for tag in scene['tags']:
if tag['name'].lower() == tagToDelete: if tag['name'].lower() == tagToDelete:
@@ -1105,7 +1121,8 @@ def manageTagggedDuplicates(deleteScenes=False, clearTag=False, setGrayListTag=F
break break
if doProcessThis == False: if doProcessThis == False:
continue continue
else: if fileNotExistToDelete:
if os.path.isfile(scene['files'][0]['path']):
continue continue
stash.Warn(f"Deleting duplicate '{DupFileName}'", toAscii=True, printTo=LOG_STASH_N_PLUGIN) stash.Warn(f"Deleting duplicate '{DupFileName}'", toAscii=True, printTo=LOG_STASH_N_PLUGIN)
if alternateTrashCanPath != "": if alternateTrashCanPath != "":

View File

@@ -32,23 +32,24 @@ html.wait, html.wait * { cursor: wait !important; }
</style> </style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script> <script>
// console.log(window.location.href); var GqlFromParam = false;
const queryString = window.location.search; const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString); const urlParams = new URLSearchParams(queryString);
console.log(urlParams); console.log(urlParams);
var GraphQl_URL = "http://localhost:9999/graphql"; var GraphQl_URL = "http://localhost:9999/graphql";
if (urlParams.get('GQL') != null && urlParams.get('GQL') === "") if (urlParams.get('GQL') != null && urlParams.get('GQL') === "")
GraphQl_URL = urlParams.get('GQL'); GraphQl_URL = urlParams.get('GQL');
GqlFromParam = true;
console.log("GQL = " + GraphQl_URL); console.log("GQL = " + GraphQl_URL);
function RunPluginDupFileManager(Mode, ActionID = 0, Async = false) { function RunPluginDupFileManager(Mode, Param = 0, Async = false) {
$('html').addClass('wait'); $('html').addClass('wait');
$("body").css("cursor", "progress"); $("body").css("cursor", "progress");
console.log("GraphQl_URL = " + GraphQl_URL + "; Mode = " + Mode + "; ActionID = " + ActionID); console.log("GraphQl_URL = " + GraphQl_URL + "; Mode = " + Mode + "; Param = " + Param);
$.ajax({method: "POST", url: GraphQl_URL, contentType: "application/json", dataType: "text", cache: Async, async: Async, $.ajax({method: "POST", url: GraphQl_URL, contentType: "application/json", dataType: "text", cache: Async, async: Async,
data: JSON.stringify({ data: JSON.stringify({
query: `mutation RunPluginOperation($plugin_id:ID!,$args:Map!){runPluginOperation(plugin_id:$plugin_id,args:$args)}`, query: `mutation RunPluginOperation($plugin_id:ID!,$args:Map!){runPluginOperation(plugin_id:$plugin_id,args:$args)}`,
variables: {"plugin_id": "DupFileManager", "args": { "Target" : ActionID, "mode":Mode}}, variables: {"plugin_id": "DupFileManager", "args": { "Target" : Param, "mode":Mode}},
}), success: function(result){ }), success: function(result){
console.log(result); console.log(result);
$('html').removeClass('wait'); $('html').removeClass('wait');
@@ -58,7 +59,7 @@ function RunPluginDupFileManager(Mode, ActionID = 0, Async = false) {
} }
$(document).ready(function(){ $(document).ready(function(){
$("button").click(function(){ $("button").click(function(){
const AddedWarn = "? This will delete the files, and remove tem from stash."; const AddedWarn = "? This will delete the files, and remove them from stash.";
console.log(this.id); console.log(this.id);
var blackliststr = ""; var blackliststr = "";
var comparestr = "less than "; var comparestr = "less than ";
@@ -76,9 +77,10 @@ $(document).ready(function(){
} }
else if (this.id === "viewreport") else if (this.id === "viewreport")
{ {
var newUrl = window.location.href; var reportUrl = window.location.href;
newUrl = newUrl.replace("DupFileManager/advance_options.html", "DuplicateTagScenes.html"); reportUrl = reportUrl.replace("DupFileManager/advance_options.html", "DuplicateTagScenes.html");
window.open(newUrl, "_blank"); console.log("reportUrl = " + reportUrl);
window.open(reportUrl, "_blank");
} }
else if (this.id === "pathToDelete" || this.id === "pathToDeleteBlacklist") else if (this.id === "pathToDelete" || this.id === "pathToDeleteBlacklist")
{ {
@@ -132,6 +134,55 @@ $(document).ready(function(){
if (confirm("Are you sure you want to delete tag scenes " + blackliststr + "having _DuplicateMarkForDeletion tags, and having path containing " + $("#pathStrToDeleteText").val() + AddedWarn)) if (confirm("Are you sure you want to delete tag scenes " + blackliststr + "having _DuplicateMarkForDeletion tags, and having path containing " + $("#pathStrToDeleteText").val() + AddedWarn))
RunPluginDupFileManager(this.id, $("#pathStrToDeleteText").val()); RunPluginDupFileManager(this.id, $("#pathStrToDeleteText").val());
} }
else if (this.id === "fileNotExistToDelete" || this.id === "fileNotExistToDeleteBlacklist")
{
if (confirm("Are you sure you want to delete tag scenes " + blackliststr + "having _DuplicateMarkForDeletion tags, and that do NOT exist in the file system?"))
RunPluginDupFileManager(this.id, true);
}
else if (this.id === "applyCombo" || this.id === "applyComboBlacklist")
{
var Blacklist = "";
if (this.id === "applyComboBlacklist")
Blacklist = "Blacklist";
var Param = "{";
if ($("#InPathCheck").prop('checked'))
Param += "\"" + "pathToDelete" + Blacklist + "\":\"" + $("#pathToDeleteText").val().replace("\\", "\\\\") + "\", ";
if ($("#sizeToDeleteCombobox").val() !== "")
Param += "\"" + "sizeToDelete" + Blacklist + $("#sizeToDeleteCombobox").val() + "\":\"" + $("#sizeToDelete").val() + "\", ";
if ($("#durationToDeleteCombobox").val() !== "")
Param += "\"" + "durationToDelete" + Blacklist + $("#durationToDeleteCombobox").val() + "\":\"" + $("#durationToDelete").val() + "\", ";
if ($("#commonResToDeleteCombobox").val() !== "")
Param += "\"" + "commonResToDelete" + Blacklist + $("#commonResToDeleteCombobox").val() + "\":\"" + $("#commonResToDelete").val() + "\", ";
if ($("#resolutionToDeleteCombobox").val() !== "")
{
if ($("#commonResToDeleteCombobox").val() !== "")
{
alert("Error: Can not select both [Common Resolution] and [Other Resolution] at the same time.");
return;
}
Param += "\"" + "resolutionToDelete" + Blacklist + $("#resolutionToDeleteCombobox").val() + "\":\"" + $("#resolutionToDelete").val() + "\", ";
}
if ($("#ratingToDeleteCombobox").val() !== "")
Param += "\"" + "ratingToDelete" + Blacklist + $("#ratingToDeleteCombobox").val() + "\":\"" + $("#ratingToDelete").val() + "\", ";
if ($("#containTagCheck").prop('checked'))
Param += "\"" + "tagToDelete" + Blacklist + "\":\"" + $("#tagToDeleteText").val() + "\", ";
if ($("#containTitleCheck").prop('checked'))
Param += "\"" + "titleToDelete" + Blacklist + "\":\"" + $("#titleToDeleteText").val() + "\", ";
if ($("#containStrInPathCheck").prop('checked'))
Param += "\"" + "pathStrToDelete" + Blacklist + "\":\"" + $("#pathStrToDeleteText").val().replace("\\", "\\\\") + "\", ";
if ($("#fileNotExistCheck").prop('checked'))
Param += "\"" + "fileNotExistToDelete" + Blacklist + "\":\"true\", ";
Param += '}';
Param = Param.replace(', }', '}');
if (Param === "{}")
{
alert("Error: Must select one or more options.");
return;
}
console.log(Param);
if (confirm("Are you sure you want to delete tag scenes " + blackliststr + "having _DuplicateMarkForDeletion tags, and having the selected options" + AddedWarn + "\nSelected options:\n" + Param))
RunPluginDupFileManager(this.id, Param);
}
}); });
}); });
function DeleteDupInPath(){ function DeleteDupInPath(){
@@ -141,19 +192,29 @@ function DeleteDupInPath(){
</head> </head>
<body> <body>
<center><table style="color:darkgreen;background-color:powderblue;"> <center><table style="color:darkgreen;background-color:powderblue;">
<tr><th>DupFileManager Advance <b style="color:red;">_DuplicateMarkForDeletion_?</b> Tagged Files Menu</th></tr> <tr><th>DupFileManager Advance <b style="color:red;">_DuplicateMarkForDeletion_?</b> Tagged Files Menu</th><th>Apply Multiple Options</th></tr>
<tr><td><center> <tr>
<td><center>
<button type="button" id="tag_duplicates_task" value="-1" title="Create new report which tags duplicates with tag name _DuplicateMarkForDeletion using user settings for [Match Duplicate Distance].">Create Duplicate Report with Tagging</button> <button type="button" id="tag_duplicates_task" value="-1" title="Create new report which tags duplicates with tag name _DuplicateMarkForDeletion using user settings for [Match Duplicate Distance].">Create Duplicate Report with Tagging</button>
<button type="button" id="viewreport" title="View duplicate file report.">View Dup Report</button> <button type="button" id="viewreport" title="View duplicate file report.">View Dup Report</button>
</center></td></tr> </center></td>
<tr><td><form id="pathToDeleteForm" action="javascript:DeleteDupInPath();" target="_self"> <td>
<label for="pathToDelete">Path:</label> <button type="button" id="applyCombo" title="Apply selected multiple options to delete scenes.">Delete</button>
<input type="text" id="pathToDeleteText" name="pathToDelete" value="C:\Downloads"> <button type="button" id="applyComboBlacklist" title="Apply selected multiple options to delete scenes in blacklist.">Delete-Blacklist</button>
</td>
</tr>
<tr>
<td><form id="pathToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="pathToDeleteText">Path:</label>
<input type="text" id="pathToDeleteText" name="pathToDeleteText" value="C:\Downloads">
<button type="button" id="pathToDelete" title="Delete tagged duplicates having file path">Delete Dup in Path</button> <button type="button" id="pathToDelete" title="Delete tagged duplicates having file path">Delete Dup in Path</button>
<button type="button" id="pathToDeleteBlacklist" title="Delete blacklist tagged duplicates having file path">Del Blacklist Dup in Path</button> <button type="button" id="pathToDeleteBlacklist" title="Delete blacklist tagged duplicates having file path">Del Blacklist Dup in Path</button>
</form> </form>
</td></tr> </td>
<tr><td><form id="sizeToDeleteForm" action="javascript:DeleteDupInPath();" target="_self"> <td><label for="InPathCheck">In-Path:</label><input type="checkbox" id="InPathCheck" name="InPathCheck" value="true"></td>
</tr>
<tr>
<td><form id="sizeToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="sizeToDelete" title="File size in bytes.">File Size (bytes):</label> <label for="sizeToDelete" title="File size in bytes.">File Size (bytes):</label>
<input type="number" id="sizeToDelete" name="sizeToDelete" title="File size in bytes." value="123456"> <input type="number" id="sizeToDelete" name="sizeToDelete" title="File size in bytes." value="123456">
<label for="sizeToDeleteLess">All:</label> <label for="sizeToDeleteLess">All:</label>
@@ -163,8 +224,17 @@ function DeleteDupInPath(){
<button type="button" id="sizeToDeleteBlacklistLess" title="Delete blacklist tagged duplicates with file size less than"><</button> <button type="button" id="sizeToDeleteBlacklistLess" title="Delete blacklist tagged duplicates with file size less than"><</button>
<button type="button" id="sizeToDeleteBlacklistGreater" title="Delete blacklist tagged duplicates with file size greater than">></button> <button type="button" id="sizeToDeleteBlacklistGreater" title="Delete blacklist tagged duplicates with file size greater than">></button>
</form> </form>
</td></tr> </td>
<tr><td><form id="durationToDeleteForm" action="javascript:DeleteDupInPath();" target="_self"> <td><label for="sizeToDeleteCombobox">Size:</label>
<select id="sizeToDeleteCombobox" name="sizeToDeleteCombobox">
<option value="" selected="selected"></option>
<option value="Less">Less</option>
<option value="Greater">Greater</option>
</select>
</td>
</tr>
<tr>
<td><form id="durationToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="durationToDelete" title="Scene duration (time) in seconds.">Duration (seconds):</label> <label for="durationToDelete" title="Scene duration (time) in seconds.">Duration (seconds):</label>
<input type="number" min="1" max="14400" id="durationToDelete" name="durationToDelete" title="Duration in seconds." value="60"> <input type="number" min="1" max="14400" id="durationToDelete" name="durationToDelete" title="Duration in seconds." value="60">
<label for="durationToDeleteLess">All:</label> <label for="durationToDeleteLess">All:</label>
@@ -174,8 +244,17 @@ function DeleteDupInPath(){
<button type="button" id="durationToDeleteBlacklistLess" title="Delete blacklist tagged duplicates with duration less than"><</button> <button type="button" id="durationToDeleteBlacklistLess" title="Delete blacklist tagged duplicates with duration less than"><</button>
<button type="button" id="durationToDeleteBlacklistGreater" title="Delete blacklist tagged duplicates with duration greater than">></button> <button type="button" id="durationToDeleteBlacklistGreater" title="Delete blacklist tagged duplicates with duration greater than">></button>
</form> </form>
</td></tr> </td>
<tr><td><form id="commonResToDeleteForm" action="javascript:DeleteDupInPath();" target="_self"> <td><label for="durationToDeleteCombobox">Duration:</label>
<select id="durationToDeleteCombobox" name="durationToDeleteCombobox">
<option value="" selected="selected"></option>
<option value="Less">Less</option>
<option value="Greater">Greater</option>
</select>
</td>
</tr>
<tr>
<td><form id="commonResToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="commonResToDelete" title="Scene commonRes.">Common Resolution:</label> <label for="commonResToDelete" title="Scene commonRes.">Common Resolution:</label>
<select id="commonResToDelete" name="commonResToDelete"> <select id="commonResToDelete" name="commonResToDelete">
<option value="76800">320x240=76800</option> <option value="76800">320x240=76800</option>
@@ -203,8 +282,18 @@ function DeleteDupInPath(){
<button type="button" id="commonResToDeleteBlacklistEq" title="Delete blacklist tagged duplicates with resolution equal to">=</button> <button type="button" id="commonResToDeleteBlacklistEq" title="Delete blacklist tagged duplicates with resolution equal to">=</button>
<button type="button" id="commonResToDeleteBlacklistGreater" title="Delete blacklist tagged duplicates with resolution greater than">></button> <button type="button" id="commonResToDeleteBlacklistGreater" title="Delete blacklist tagged duplicates with resolution greater than">></button>
</form> </form>
</td></tr> </td>
<tr><td><form id="tagToDeleteForm" action="javascript:DeleteDupInPath();" target="_self"> <td><label for="commonResToDeleteCombobox">Resolution:</label>
<select id="commonResToDeleteCombobox" name="commonResToDeleteCombobox">
<option value="" selected="selected"></option>
<option value="Less">Less</option>
<option value="Eq">Equal</option>
<option value="Greater">Greater</option>
</select>
</td>
</tr>
<tr>
<td><form id="tagToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="tagToDelete" title="Scene with tag.">Tag:</label> <label for="tagToDelete" title="Scene with tag.">Tag:</label>
<input type="text" id="tagToDeleteText" name="tagToDelete" title="tag name." value="redhead"> <input type="text" id="tagToDeleteText" name="tagToDelete" title="tag name." value="redhead">
<label for="tagToDelete">All:</label> <label for="tagToDelete">All:</label>
@@ -212,8 +301,11 @@ function DeleteDupInPath(){
<label for="tagToDeleteBlacklist">Blacklist:</label> <label for="tagToDeleteBlacklist">Blacklist:</label>
<button type="button" id="tagToDeleteBlacklist" title="Delete blacklist tagged duplicates with tag name">Contains</button> <button type="button" id="tagToDeleteBlacklist" title="Delete blacklist tagged duplicates with tag name">Contains</button>
</form> </form>
</td></tr> </td>
<tr><td><form id="titleToDeleteForm" action="javascript:DeleteDupInPath();" target="_self"> <td><label for="containTagCheck">Contains Tag:</label><input type="checkbox" id="containTagCheck" name="containTagCheck" value="true"></td>
</tr>
<tr>
<td><form id="titleToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="titleToDelete" title="Scene having value in title.">Title:</label> <label for="titleToDelete" title="Scene having value in title.">Title:</label>
<input type="text" id="titleToDeleteText" name="titleToDelete" title="String to search for in title." value="mature"> <input type="text" id="titleToDeleteText" name="titleToDelete" title="String to search for in title." value="mature">
<label for="titleToDelete">All:</label> <label for="titleToDelete">All:</label>
@@ -221,8 +313,11 @@ function DeleteDupInPath(){
<label for="titleToDeleteBlacklist">Blacklist:</label> <label for="titleToDeleteBlacklist">Blacklist:</label>
<button type="button" id="titleToDeleteBlacklist" title="Delete blacklist tagged duplicates with title name including value">Contains</button> <button type="button" id="titleToDeleteBlacklist" title="Delete blacklist tagged duplicates with title name including value">Contains</button>
</form> </form>
</td></tr> </td>
<tr><td><form id="pathStrToDeleteForm" action="javascript:DeleteDupInPath();" target="_self"> <td><label for="containTitleCheck">Contains Title:</label><input type="checkbox" id="containTitleCheck" name="containTitleCheck" value="true"></td>
</tr>
<tr>
<td><form id="pathStrToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="pathStrToDelete" pathStr="Scene having value in path.">Path String:</label> <label for="pathStrToDelete" pathStr="Scene having value in path.">Path String:</label>
<input type="text" id="pathStrToDeleteText" name="pathStrToDelete" pathStr="String to search for in path." value="blond"> <input type="text" id="pathStrToDeleteText" name="pathStrToDelete" pathStr="String to search for in path." value="blond">
<label for="pathStrToDelete">All:</label> <label for="pathStrToDelete">All:</label>
@@ -230,8 +325,11 @@ function DeleteDupInPath(){
<label for="pathStrToDeleteBlacklist">Blacklist:</label> <label for="pathStrToDeleteBlacklist">Blacklist:</label>
<button type="button" id="pathStrToDeleteBlacklist" pathStr="Delete blacklist tagged duplicates with path having value">Contains</button> <button type="button" id="pathStrToDeleteBlacklist" pathStr="Delete blacklist tagged duplicates with path having value">Contains</button>
</form> </form>
</td></tr> </td>
<tr><td><form id="ratingToDeleteForm" action="javascript:DeleteDupInPath();" target="_self"> <td><label for="containStrInPathCheck">Text in Path:</label><input type="checkbox" id="containStrInPathCheck" name="containStrInPathCheck" value="true"></td>
</tr>
<tr>
<td><form id="ratingToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="ratingToDelete" title="Scene rating.">Rating:</label> <label for="ratingToDelete" title="Scene rating.">Rating:</label>
<input type="number" min="1" max="5" id="ratingToDelete" name="ratingToDelete" title="Scene rating (1, 2, 3, 4, or 5)" value="1"> <input type="number" min="1" max="5" id="ratingToDelete" name="ratingToDelete" title="Scene rating (1, 2, 3, 4, or 5)" value="1">
<label for="ratingToDeleteLess">All:</label> <label for="ratingToDeleteLess">All:</label>
@@ -243,8 +341,27 @@ function DeleteDupInPath(){
<button type="button" id="ratingToDeleteBlacklistEq" title="Delete blacklist tagged duplicates with rating equal to">=</button> <button type="button" id="ratingToDeleteBlacklistEq" title="Delete blacklist tagged duplicates with rating equal to">=</button>
<button type="button" id="ratingToDeleteBlacklistGreater" title="Delete blacklist tagged duplicates with file rating greater than">></button> <button type="button" id="ratingToDeleteBlacklistGreater" title="Delete blacklist tagged duplicates with file rating greater than">></button>
</form> </form>
</td></tr> </td>
<tr><td><form id="resolutionToDeleteForm" action="javascript:DeleteDupInPath();" target="_self"> <td><label for="ratingToDeleteCombobox">Rating:</label>
<select id="ratingToDeleteCombobox" name="ratingToDeleteCombobox">
<option value="" selected="selected"></option>
<option value="Less">Less</option>
<option value="Eq">Equal</option>
<option value="Greater">Greater</option>
</select>
</td>
</tr>
<tr>
<td>
<label for="fileNotExistToDelete">All:</label>
<button type="button" id="fileNotExistToDelete" title="Delete tagged duplicates for which file does NOT exist.">Delete Files That do Not Exist</button>
<label for="fileNotExistToDeleteBlacklist">Blacklist:</label>
<button type="button" id="fileNotExistToDeleteBlacklist" title="Delete blacklist tagged duplicates for which file does NOT exist.">Delete Files That do Not Exist</button>
</td>
<td><label for="fileNotExistCheck">File Not Exist:</label><input type="checkbox" id="fileNotExistCheck" name="fileNotExistCheck" value="true"></td>
</tr>
<tr>
<td><form id="resolutionToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="resolutionToDelete" title="Scene resolution.">Other Resolution:</label> <label for="resolutionToDelete" title="Scene resolution.">Other Resolution:</label>
<select id="resolutionToDelete" name="resolutionToDelete"> <select id="resolutionToDelete" name="resolutionToDelete">
<option value="19200">120x160=19200</option> <option value="19200">120x160=19200</option>
@@ -1662,7 +1779,16 @@ function DeleteDupInPath(){
<button type="button" id="resolutionToDeleteBlacklistEq" title="Delete blacklist tagged duplicates with resolution equal to">=</button> <button type="button" id="resolutionToDeleteBlacklistEq" title="Delete blacklist tagged duplicates with resolution equal to">=</button>
<button type="button" id="resolutionToDeleteBlacklistGreater" title="Delete blacklist tagged duplicates with resolution greater than">></button> <button type="button" id="resolutionToDeleteBlacklistGreater" title="Delete blacklist tagged duplicates with resolution greater than">></button>
</form> </form>
</td></tr> </td>
<td><label for="resolutionToDeleteCombobox">Resolution:</label>
<select id="resolutionToDeleteCombobox" name="resolutionToDeleteCombobox">
<option value="" selected="selected"></option>
<option value="Less">Less</option>
<option value="Eq">Equal</option>
<option value="Greater">Greater</option>
</select>
</td>
</tr>
</table></center> </table></center>
<div id="div1"></div> <div id="div1"></div>
<br> <br>

View File

@@ -3,8 +3,13 @@
# Get the latest developers version from following link: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/FileMonitor # Get the latest developers version from following link: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/FileMonitor
# Note: To call this script outside of Stash, pass argument --url and the Stash URL. # Note: To call this script outside of Stash, pass argument --url and the Stash URL.
# Example: python filemonitor.py --url http://localhost:9999 # Example: python filemonitor.py --url http://localhost:9999
import ModulesValidate try:
ModulesValidate.modulesInstalled(["stashapp-tools", "watchdog", "schedule", "requests"]) import ModulesValidate
ModulesValidate.modulesInstalled(["stashapp-tools", "watchdog", "schedule", "requests"])
except Exception as e:
import traceback, sys
tb = traceback.format_exc()
print(f"ModulesValidate Exception. Error: {e}\nTraceBack={tb}", file=sys.stderr)
from StashPluginHelper import StashPluginHelper from StashPluginHelper import StashPluginHelper
import os, sys, time, pathlib, argparse, platform, traceback, logging import os, sys, time, pathlib, argparse, platform, traceback, logging
from StashPluginHelper import taskQueue from StashPluginHelper import taskQueue

View File

@@ -2,8 +2,14 @@
# By David Maisonave (aka Axter) Jul-2024 (https://www.axter.com/) # By David Maisonave (aka Axter) Jul-2024 (https://www.axter.com/)
# Get the latest developers version from following link: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/RenameFile # Get the latest developers version from following link: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/RenameFile
# Based on source code from https://github.com/Serechops/Serechops-Stash/tree/main/plugins/Renamer # Based on source code from https://github.com/Serechops/Serechops-Stash/tree/main/plugins/Renamer
import ModulesValidate try:
ModulesValidate.modulesInstalled(["stashapp-tools", "requests"]) import ModulesValidate
ModulesValidate.modulesInstalled(["stashapp-tools", "requests"])
except Exception as e:
import traceback, sys
tb = traceback.format_exc()
print(f"ModulesValidate Exception. Error: {e}\nTraceBack={tb}", file=sys.stderr)
import os, sys, shutil, json, hashlib, pathlib, logging, time, traceback import os, sys, shutil, json, hashlib, pathlib, logging, time, traceback
from pathlib import Path from pathlib import Path
import stashapi.log as log # Importing stashapi.log as log for critical events ONLY import stashapi.log as log # Importing stashapi.log as log for critical events ONLY