forked from Github/Axter-Stash
v1.1.2
- Moved link to [**Advance Duplicate File Menu**] to https://stash.axter.com/1.1.2/advance_options.html - This allows the Advance Menu to be accessed by Chrome, Edge and other Chrome based browsers which don't allow accessing local links from a non-local URL. - Added additional warnings when detecting Chrome based browsers and when moving from non-local link to local link. - Moved htmlReportPrefix field from the DupFileManager_report_config.py to DupFileManager_report_header. - This was needed because Python on Docker gives an error when using tripple quoted strings. - Made advance_options.html HTML5 compliance. - Added additional details returned by getLocalDupReportPath to include (IS_DOCKER, ReportUrl, AdvMenuUrl, apikey, & LocalDir).
This commit is contained in:
133
Docker/CreateContainer.cmd
Normal file
133
Docker/CreateContainer.cmd
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
:: This file is to create Stash Docker containers, and should be copied and called from the following path:
|
||||||
|
:: C:\Users\MyUserName\AppData\Local\Docker\wsl\CreateContainer.cmd
|
||||||
|
:: Example usage:
|
||||||
|
:: CreateContainer.cmd MyContainerName "stashapp/stash:latest" 9998
|
||||||
|
:: Example with shared mount paths:
|
||||||
|
:: CreateContainer.cmd ContainerName1 "stashapp/stash:latest" 9991 C:\MySharedMountPath C:\Another\Shared\Folder
|
||||||
|
:: Example adding Stash IMAGE and container:
|
||||||
|
:: CreateContainer.cmd v0.27.2 "stashapp/stash:v0.27.2" 9997 PULL
|
||||||
|
:: Example with DLNA:
|
||||||
|
:: CreateContainer.cmd v272 "stashapp/stash:v0.27.2" 9996 C:\downloads DLNA
|
||||||
|
:: Example skipping docker-compose:
|
||||||
|
:: CreateContainer.cmd ContainerName "stashapp/stash:v0.26.2" 9992 C:\Videos SKIP
|
||||||
|
set NewContainerName=%1
|
||||||
|
:: Example image arguments:stashapp/stash:latest, stashapp/stash:v0.27.2, stashapp/stash:v0.26.2
|
||||||
|
set Image=%2
|
||||||
|
:: Example Port Numbers: 9999, 9990, 9991, 9995, 9998
|
||||||
|
set STASH_PORT=%3
|
||||||
|
:: The SharedMountPath's variables are optional arguments, and can be empty.
|
||||||
|
:: Use SharedMountPath's to specify shared paths that are mounted as READ-ONLY.
|
||||||
|
:: Example SharedMountPath: C:\Videos, E:\MyMedia, Z:\MyVideoCollections, C:\Users\MyUserName\Videos, C:\Users\MyUserName\download
|
||||||
|
set SharedMountPath=%4
|
||||||
|
set SharedMountPath2=%5
|
||||||
|
set SharedMountPath3=%6
|
||||||
|
set SharedMountPath4=%7
|
||||||
|
set SharedMountPath5=%8
|
||||||
|
set VariableArg=%9
|
||||||
|
set SkipDockerCompose=
|
||||||
|
set DLNAFunctionality="no"
|
||||||
|
set PullDockerStashImage=
|
||||||
|
if [%VariableArg%]==[DLNA] (set DLNAFunctionality=yes)
|
||||||
|
if [%VariableArg%]==[SKIP] (set SkipDockerCompose=yes)
|
||||||
|
if [%VariableArg%]==[PULL] (set PullDockerStashImage=yes)
|
||||||
|
if [%SharedMountPath%]==[DLNA] (set DLNAFunctionality=yes) & (set SharedMountPath=)
|
||||||
|
if [%SharedMountPath%]==[SKIP] (set SkipDockerCompose=yes) & (set SharedMountPath=)
|
||||||
|
if [%SharedMountPath%]==[PULL] (set PullDockerStashImage=yes) & (set SharedMountPath=)
|
||||||
|
if [%SharedMountPath2%]==[DLNA] (set DLNAFunctionality=yes) & (set SharedMountPath2=)
|
||||||
|
if [%SharedMountPath2%]==[SKIP] (set SkipDockerCompose=yes) & (set SharedMountPath2=)
|
||||||
|
if [%SharedMountPath2%]==[PULL] (set PullDockerStashImage=yes) & (set SharedMountPath2=)
|
||||||
|
if [%SharedMountPath3%]==[DLNA] (set DLNAFunctionality=yes) & (set SharedMountPath3=)
|
||||||
|
if [%SharedMountPath3%]==[SKIP] (set SkipDockerCompose=yes) & (set SharedMountPath3=)
|
||||||
|
if [%SharedMountPath3%]==[PULL] (set PullDockerStashImage=yes) & (set SharedMountPath3=)
|
||||||
|
if [%SharedMountPath4%]==[DLNA] (set DLNAFunctionality=yes) & (set SharedMountPath4=)
|
||||||
|
if [%SharedMountPath4%]==[SKIP] (set SkipDockerCompose=yes) & (set SharedMountPath4=)
|
||||||
|
if [%SharedMountPath4%]==[PULL] (set PullDockerStashImage=yes) & (set SharedMountPath4=)
|
||||||
|
if [%SharedMountPath5%]==[DLNA] (set DLNAFunctionality=yes) & (set SharedMountPath5=)
|
||||||
|
if [%SharedMountPath5%]==[SKIP] (set SkipDockerCompose=yes) & (set SharedMountPath5=)
|
||||||
|
if [%SharedMountPath5%]==[PULL] (set PullDockerStashImage=yes) & (set SharedMountPath5=)
|
||||||
|
echo SkipDockerCompose = %SkipDockerCompose% ; DLNAFunctionality = %DLNAFunctionality%
|
||||||
|
set DockerComposeFile="docker-compose.yml"
|
||||||
|
|
||||||
|
if [%NewContainerName%]==[] goto :MissingArgumentNewContainerName
|
||||||
|
goto :HaveVariableNewContainerName
|
||||||
|
:MissingArgumentNewContainerName
|
||||||
|
set /p NewContainerName="Enter the new container name: "
|
||||||
|
:HaveVariableNewContainerName
|
||||||
|
|
||||||
|
if [%Image%]==[] goto :MissingArgumentImage
|
||||||
|
goto :HaveVariableImage
|
||||||
|
:MissingArgumentImage
|
||||||
|
set /p Image="Enter the image name: "
|
||||||
|
:HaveVariableImage
|
||||||
|
|
||||||
|
if [%STASH_PORT%]==[] goto :MissingArgumentSTASH_PORT
|
||||||
|
goto :HaveVariableSTASH_PORT
|
||||||
|
:MissingArgumentSTASH_PORT
|
||||||
|
set /p STASH_PORT="Enter the Stash port number: "
|
||||||
|
:HaveVariableSTASH_PORT
|
||||||
|
|
||||||
|
if exist %NewContainerName%\ (
|
||||||
|
echo %NewContainerName% already exists.
|
||||||
|
) else (
|
||||||
|
echo creating folder %NewContainerName%
|
||||||
|
mkdir %NewContainerName%
|
||||||
|
)
|
||||||
|
cd %NewContainerName%
|
||||||
|
echo DockerComposeFile=%DockerComposeFile%; NewContainerName=%NewContainerName%; Image=%Image%; STASH_PORT=%STASH_PORT%; DLNAFunctionality=%DLNAFunctionality%; SharedMountPath=%SharedMountPath%; SharedMountPath1=%SharedMountPath1%; SharedMountPath2=%SharedMountPath2%
|
||||||
|
echo services:> %DockerComposeFile%
|
||||||
|
echo stash:>> %DockerComposeFile%
|
||||||
|
echo image: %Image%>> %DockerComposeFile%
|
||||||
|
echo container_name: %NewContainerName%>> %DockerComposeFile%
|
||||||
|
echo restart: unless-stopped>> %DockerComposeFile%
|
||||||
|
if [%DLNAFunctionality%]==[yes] goto :DoDLNA_Functionality
|
||||||
|
echo ports:>> %DockerComposeFile%
|
||||||
|
echo - "%STASH_PORT%:9999">> %DockerComposeFile%
|
||||||
|
goto :SkipDLNA_Functionality
|
||||||
|
:DoDLNA_Functionality
|
||||||
|
echo network_mode: host>> %DockerComposeFile%
|
||||||
|
:SkipDLNA_Functionality
|
||||||
|
echo logging:>> %DockerComposeFile%
|
||||||
|
echo driver: "json-file">> %DockerComposeFile%
|
||||||
|
echo options:>> %DockerComposeFile%
|
||||||
|
echo max-file: "10">> %DockerComposeFile%
|
||||||
|
echo max-size: "2m">> %DockerComposeFile%
|
||||||
|
echo environment:>> %DockerComposeFile%
|
||||||
|
echo - STASH_STASH=/data/>> %DockerComposeFile%
|
||||||
|
echo - STASH_GENERATED=/generated/>> %DockerComposeFile%
|
||||||
|
echo - STASH_METADATA=/metadata/>> %DockerComposeFile%
|
||||||
|
echo - STASH_CACHE=/cache/>> %DockerComposeFile%
|
||||||
|
if [%DLNAFunctionality%]==[yes] goto :DoDLNA_Functionality_pt2
|
||||||
|
echo - STASH_PORT=9999>> %DockerComposeFile%
|
||||||
|
goto :SkipDLNA_Functionality_pt2
|
||||||
|
:DoDLNA_Functionality_pt2
|
||||||
|
echo - STASH_PORT=%STASH_PORT%>> %DockerComposeFile%
|
||||||
|
:SkipDLNA_Functionality_pt2
|
||||||
|
echo volumes:>> %DockerComposeFile%
|
||||||
|
echo - /etc/localtime:/etc/localtime:ro>> %DockerComposeFile%
|
||||||
|
echo - ./config:/root/.stash>> %DockerComposeFile%
|
||||||
|
echo - ./data:/data>> %DockerComposeFile%
|
||||||
|
echo - ./metadata:/metadata>> %DockerComposeFile%
|
||||||
|
echo - ./cache:/cache>> %DockerComposeFile%
|
||||||
|
echo - ./blobs:/blobs>> %DockerComposeFile%
|
||||||
|
echo - ./generated:/generated>> %DockerComposeFile%
|
||||||
|
if [%SharedMountPath%]==[] goto :SkipSharedMountPaths
|
||||||
|
echo - %SharedMountPath%:/external:ro>> %DockerComposeFile%
|
||||||
|
if [%SharedMountPath2%]==[] goto :SkipSharedMountPaths
|
||||||
|
echo - %SharedMountPath2%:/external2:ro>> %DockerComposeFile%
|
||||||
|
if [%SharedMountPath3%]==[] goto :SkipSharedMountPaths
|
||||||
|
echo - %SharedMountPath3%:/external3:ro>> %DockerComposeFile%
|
||||||
|
if [%SharedMountPath4%]==[] goto :SkipSharedMountPaths
|
||||||
|
echo - %SharedMountPath4%:/external4:ro>> %DockerComposeFile%
|
||||||
|
if [%SharedMountPath5%]==[] goto :SkipSharedMountPaths
|
||||||
|
echo - %SharedMountPath5%:/external5:ro>> %DockerComposeFile%
|
||||||
|
:SkipSharedMountPaths
|
||||||
|
|
||||||
|
if [%SkipDockerCompose%] NEQ [] goto :DoNot_DockerCompose
|
||||||
|
if [%PullDockerStashImage%] NEQ [yes] goto :SkipPullDockerStashImage
|
||||||
|
docker pull %Image%
|
||||||
|
:SkipPullDockerStashImage
|
||||||
|
docker-compose up -d
|
||||||
|
:DoNot_DockerCompose
|
||||||
|
cd ..
|
||||||
|
|
||||||
@@ -1,16 +1,5 @@
|
|||||||
(function () {
|
(function () {
|
||||||
// export default withRouter(Header);
|
const isChrome = !!window.chrome;
|
||||||
// const { withRouter } = window.PluginApi.libraries.ReactRouterDOM;
|
|
||||||
// class Header extends Component {
|
|
||||||
// constructor(props) {
|
|
||||||
// super(props);
|
|
||||||
// }
|
|
||||||
// render() {
|
|
||||||
// const path = this.props.location.pathname.slice(1);
|
|
||||||
// return ("<div><h1>{path}</h1>foofoo2</div>");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
var isChrome = !!window.chrome;
|
|
||||||
const PluginApi = window.PluginApi;
|
const PluginApi = window.PluginApi;
|
||||||
const React = PluginApi.React;
|
const React = PluginApi.React;
|
||||||
const { Component } = PluginApi.React;
|
const { Component } = PluginApi.React;
|
||||||
@@ -22,18 +11,17 @@
|
|||||||
var myArray = rootPath.split("/");
|
var myArray = rootPath.split("/");
|
||||||
rootPath = myArray[0] + "//" + myArray[2]
|
rootPath = myArray[0] + "//" + myArray[2]
|
||||||
console.log("rootPath = " + rootPath);
|
console.log("rootPath = " + rootPath);
|
||||||
var AsyncResults = null;
|
|
||||||
function RunPluginDupFileManager(Mode, DataType = "text", Async = false, ActionID = 0) {
|
function RunPluginDupFileManager(Mode, DataType = "text", Async = false, ActionID = 0) {
|
||||||
AsyncResults = null;
|
|
||||||
const AjaxData = $.ajax({method: "POST", url: "/graphql", contentType: "application/json", dataType: DataType, cache: Async, async: Async,
|
const AjaxData = $.ajax({method: "POST", url: "/graphql", contentType: "application/json", dataType: DataType, 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" : ActionID, "mode":Mode}},
|
||||||
}), success: function(result){
|
}), success: function(result){
|
||||||
AsyncResults = result;
|
if (DataType == "text"){
|
||||||
console.log(AsyncResults);
|
console.log("result=" + result);
|
||||||
if (DataType == "text")
|
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
console.log("JSON result=" + JSON.stringify(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -44,18 +32,24 @@
|
|||||||
console.log(AjaxData.responseText);
|
console.log(AjaxData.responseText);
|
||||||
return AjaxData.responseText;
|
return AjaxData.responseText;
|
||||||
}
|
}
|
||||||
console.log(AjaxData.responseJSON);
|
JsonStr = AjaxData.responseJSON.data.runPluginOperation.replaceAll("'", "\"");
|
||||||
return JSON.parse(AjaxData.responseJSON.data.runPluginOperation.replaceAll("'", "\""));
|
console.log("JSON runPluginOperation = " + JsonStr);
|
||||||
|
return JSON.parse(JsonStr);
|
||||||
}
|
}
|
||||||
var LocalDupReportExist = false;
|
var LocalDupReportExist = false;
|
||||||
var AdvanceMenuOptionUrl = "";
|
var AdvanceMenuOptionUrl = "";
|
||||||
|
var apiKey = "";
|
||||||
|
var UrlParam = "";
|
||||||
|
var IS_DOCKER = "";
|
||||||
function GetLocalDuplicateReportPath(){
|
function GetLocalDuplicateReportPath(){
|
||||||
var LocalDuplicateReport = RunPluginDupFileManager("getLocalDupReportPath", "json");
|
var LocalDuplicateReport = RunPluginDupFileManager("getLocalDupReportPath", "json");
|
||||||
var LocalDuplicateReportPath = "file://" + LocalDuplicateReport.Path;
|
var LocalDuplicateReportPath = "file://" + LocalDuplicateReport.Path;
|
||||||
console.log(LocalDuplicateReportPath);
|
apiKey = LocalDuplicateReport.apiKey;
|
||||||
// AdvanceMenuOptionUrl = LocalDuplicateReportPath.replace("report\\DuplicateTagScenes.html", "advance_options.html" + "?GQL=" + rootPath);
|
IS_DOCKER = LocalDuplicateReport.IS_DOCKER;
|
||||||
AdvanceMenuOptionUrl = LocalDuplicateReportPath.replace("report\\DuplicateTagScenes.html", "advance_options.html");
|
UrlParam = "?GQL=" + rootPath + "/graphql&IS_DOCKER=" + IS_DOCKER + "&apiKey=" + apiKey;
|
||||||
console.log(AdvanceMenuOptionUrl);
|
console.log("LocalDuplicateReportPath=" + JSON.stringify(LocalDuplicateReportPath) + "; document.cookie=" + document.cookie);
|
||||||
|
AdvanceMenuOptionUrl = LocalDuplicateReport.AdvMenuUrl + UrlParam;
|
||||||
|
console.log("AdvanceMenuOptionUrl=" + AdvanceMenuOptionUrl);
|
||||||
LocalDupReportExist = LocalDuplicateReport.LocalDupReportExist;
|
LocalDupReportExist = LocalDuplicateReport.LocalDupReportExist;
|
||||||
return LocalDuplicateReportPath;
|
return LocalDuplicateReportPath;
|
||||||
}
|
}
|
||||||
@@ -77,16 +71,14 @@
|
|||||||
return React.createElement("div", null,
|
return React.createElement("div", null,
|
||||||
React.createElement("div", {style:{"background-color":"yellow", color:"red"}}, ChromeNotice),
|
React.createElement("div", {style:{"background-color":"yellow", color:"red"}}, ChromeNotice),
|
||||||
React.createElement("h5", null, ShowReportChromeHeader),
|
React.createElement("h5", null, ShowReportChromeHeader),
|
||||||
React.createElement("a", {href: LocalDuplicateReportPath, style:{color:"pink"}, title: ShowReportButtonToolTip}, LocalDuplicateReportPath));
|
React.createElement("a", {href: LocalDuplicateReportPath, style:{color:"pink"}, title: ShowReportButtonToolTip, target:"_blank"}, LocalDuplicateReportPath));
|
||||||
return React.createElement("a", { href: LocalDuplicateReportPath, title: ShowReportButtonToolTip}, React.createElement(Button, null, ButtonText));
|
return React.createElement("a", { href: LocalDuplicateReportPath, title: ShowReportButtonToolTip, target:"_blank"}, React.createElement(Button, null, ButtonText));
|
||||||
}
|
}
|
||||||
function GetAdvanceMenuButton()
|
function GetAdvanceMenuButton()
|
||||||
{
|
{
|
||||||
if (isChrome)
|
return React.createElement("a", { href: "https://stash.axter.com/1.1.2/advance_options.html" + UrlParam, title: "Open link to the [Advance Duplicate File Menu].", target:"_blank"}, React.createElement(Button, null, "Show [Advance Duplicate File Menu]"));
|
||||||
return React.createElement("div", null,
|
// The following does not work with Chrome, or with an apiKey, or with a non-standard Stash URL.
|
||||||
React.createElement("h5", null, "The following is the link to the [Advance Duplicate File Menu]"),
|
//return React.createElement("a", { href: AdvanceMenuOptionUrl, title: "Open link to the [Advance Duplicate File Menu].", target:"_blank"}, React.createElement(Button, null, "Show [Advance Duplicate File Menu]"));
|
||||||
React.createElement("a", {href: AdvanceMenuOptionUrl, style:{color:"pink"}}, AdvanceMenuOptionUrl));
|
|
||||||
return React.createElement("a", { href: AdvanceMenuOptionUrl, title: "Open link to the [Advance Duplicate File Menu]."}, React.createElement(Button, null, "Show [Advance Duplicate File Menu]"));
|
|
||||||
}
|
}
|
||||||
function GetCreateReportNoTagButton(ButtonText){return React.createElement(Link, { to: "/DupFileManager_CreateReportWithNoTagging", title: CreateReportNoTagButtonToolTip }, React.createElement(Button, null, ButtonText));}
|
function GetCreateReportNoTagButton(ButtonText){return React.createElement(Link, { to: "/DupFileManager_CreateReportWithNoTagging", title: CreateReportNoTagButtonToolTip }, React.createElement(Button, null, ButtonText));}
|
||||||
function GetCreateReportButton(ButtonText){return React.createElement(Link, { to: "/DupFileManager_CreateReport", title: CreateReportButtonToolTip }, React.createElement(Button, null, ButtonText));}
|
function GetCreateReportButton(ButtonText){return React.createElement(Link, { to: "/DupFileManager_CreateReport", title: CreateReportButtonToolTip }, React.createElement(Button, null, ButtonText));}
|
||||||
|
|||||||
@@ -153,6 +153,11 @@ tagLongDurationLowRes = stash.Setting('tagLongDurationLowRes')
|
|||||||
bitRateIsImporantComp = stash.Setting('bitRateIsImporantComp')
|
bitRateIsImporantComp = stash.Setting('bitRateIsImporantComp')
|
||||||
codecIsImporantComp = stash.Setting('codecIsImporantComp')
|
codecIsImporantComp = stash.Setting('codecIsImporantComp')
|
||||||
|
|
||||||
|
DupFileManagerFolder = f"{stash.PLUGINS_PATH}{os.sep}community{os.sep}DupFileManager"
|
||||||
|
if not os.path.isdir(DupFileManagerFolder):
|
||||||
|
DupFileManagerFolder = f"{stash.PLUGINS_PATH}{os.sep}DupFileManager"
|
||||||
|
reportHeader = f"{DupFileManagerFolder}{os.sep}DupFileManager_report_header"
|
||||||
|
|
||||||
excludeFromReportIfSignificantTimeDiff = False
|
excludeFromReportIfSignificantTimeDiff = False
|
||||||
htmlReportPaginate = stash.Setting('htmlReportPaginate')
|
htmlReportPaginate = stash.Setting('htmlReportPaginate')
|
||||||
htmlIncludeImagePreview = stash.Setting('htmlIncludeImagePreview')
|
htmlIncludeImagePreview = stash.Setting('htmlIncludeImagePreview')
|
||||||
@@ -570,8 +575,13 @@ def getPath(Scene, getParent = False):
|
|||||||
return pathlib.Path(path).resolve().parent
|
return pathlib.Path(path).resolve().parent
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
htmlReportPrefix = None
|
||||||
def getHtmlReportTableRow(qtyResults, tagDuplicates):
|
def getHtmlReportTableRow(qtyResults, tagDuplicates):
|
||||||
htmlReportPrefix = stash.Setting('htmlReportPrefix')
|
global htmlReportPrefix
|
||||||
|
if htmlReportPrefix != None:
|
||||||
|
return htmlReportPrefix
|
||||||
|
with open(reportHeader, 'r') as file:
|
||||||
|
htmlReportPrefix = file.read()
|
||||||
htmlReportPrefix = htmlReportPrefix.replace('http://127.0.0.1:9999/graphql', stash.url)
|
htmlReportPrefix = htmlReportPrefix.replace('http://127.0.0.1:9999/graphql', stash.url)
|
||||||
htmlReportPrefix = htmlReportPrefix.replace('http://localhost:9999/graphql', stash.url)
|
htmlReportPrefix = htmlReportPrefix.replace('http://localhost:9999/graphql', stash.url)
|
||||||
if 'apiKey' in stash.STASH_CONFIGURATION and stash.STASH_CONFIGURATION['apiKey'] != "":
|
if 'apiKey' in stash.STASH_CONFIGURATION and stash.STASH_CONFIGURATION['apiKey'] != "":
|
||||||
@@ -654,8 +664,7 @@ def doesDelCandidateHaveMetadataNotInDupToKeep(DupFile, DupFileToKeep, listName,
|
|||||||
break
|
break
|
||||||
return DupToKeepMissingItem, DelCandidateMissingItem
|
return DupToKeepMissingItem, DelCandidateMissingItem
|
||||||
|
|
||||||
|
htmlReportNameFolder = f"{DupFileManagerFolder}{os.sep}report"
|
||||||
htmlReportNameFolder = f"{stash.PLUGINS_PATH}{os.sep}DupFileManager{os.sep}report"
|
|
||||||
htmlReportName = f"{htmlReportNameFolder}{os.sep}{stash.Setting('htmlReportName')}"
|
htmlReportName = f"{htmlReportNameFolder}{os.sep}{stash.Setting('htmlReportName')}"
|
||||||
htmlReportTableRow = stash.Setting('htmlReportTableRow')
|
htmlReportTableRow = stash.Setting('htmlReportTableRow')
|
||||||
htmlReportVideoPreview = f"width='{htmlVideoPreviewWidth}' height='{htmlVideoPreviewHeight}' {stash.Setting('htmlReportVideoPreview')} "
|
htmlReportVideoPreview = f"width='{htmlVideoPreviewWidth}' height='{htmlVideoPreviewHeight}' {stash.Setting('htmlReportVideoPreview')} "
|
||||||
@@ -1747,7 +1756,14 @@ def mergeTags(inputScene1=None):
|
|||||||
def getLocalDupReportPath():
|
def getLocalDupReportPath():
|
||||||
htmlReportExist = "true" if os.path.isfile(htmlReportName) else "false"
|
htmlReportExist = "true" if os.path.isfile(htmlReportName) else "false"
|
||||||
localPath = htmlReportName.replace("\\", "\\\\")
|
localPath = htmlReportName.replace("\\", "\\\\")
|
||||||
jsonReturn = "{'LocalDupReportExist' : " + f"{htmlReportExist}" + ", 'Path': '" + f"{localPath}" + "'}"
|
LocalDir = htmlReportNameFolder.replace("\\", "\\\\")
|
||||||
|
ReportUrl = f"file://{htmlReportName.replace(os.sep, '/')}"
|
||||||
|
AdvMenuUrl = f"file://{stash.PLUGINS_PATH.replace(os.sep, '/')}/DupFileManager/advance_options.html"
|
||||||
|
ReportUrlDir = f"file://{htmlReportNameFolder.replace(os.sep, '/')}"
|
||||||
|
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}' {apikey_json}" + "}"
|
||||||
stash.Log(f"Sending json value {jsonReturn}")
|
stash.Log(f"Sending json value {jsonReturn}")
|
||||||
sys.stdout.write(jsonReturn)
|
sys.stdout.write(jsonReturn)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: DupFileManager
|
name: DupFileManager
|
||||||
description: Manages duplicate files.
|
description: Manages duplicate files.
|
||||||
version: 1.1.1
|
version: 1.1.2
|
||||||
url: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/DupFileManager
|
url: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/DupFileManager
|
||||||
ui:
|
ui:
|
||||||
javascript:
|
javascript:
|
||||||
|
|||||||
@@ -29,409 +29,6 @@ report_config = {
|
|||||||
"htmlReportBackgroundColor" : "#f0f5f5",
|
"htmlReportBackgroundColor" : "#f0f5f5",
|
||||||
# The report text color
|
# The report text color
|
||||||
"htmlReportTextColor" : "black",
|
"htmlReportTextColor" : "black",
|
||||||
# HTML report prefix, before table listing
|
|
||||||
"htmlReportPrefix" : """<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Stash Duplicate Report</title>
|
|
||||||
<style>
|
|
||||||
h2 {text-align: center;}
|
|
||||||
table, th, td {border:1px solid black;}
|
|
||||||
.inline {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
.scene-details{text-align: center;font-size: small;}
|
|
||||||
.reason-details{text-align: left;font-size: small;}
|
|
||||||
.link-items{text-align: center;font-size: small;}
|
|
||||||
ul {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 1px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.large {
|
|
||||||
position: absolute;
|
|
||||||
left: -9999px;
|
|
||||||
}
|
|
||||||
li:hover .large {
|
|
||||||
left: 20px;
|
|
||||||
top: -150px;
|
|
||||||
}
|
|
||||||
.large-image {
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 1px 1px 3px 3px rgba(127, 127, 127, 0.15);;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="https://axter.com/js/easyui/themes/black/easyui.css">
|
|
||||||
<link rel="stylesheet" type="text/css" href="https://axter.com/js/easyui/themes/icon.css">
|
|
||||||
<script type="text/javascript" src="https://axter.com/js/jquery-3.7.1.min.js"></script>
|
|
||||||
<script type="text/javascript" src="https://axter.com/js/easyui/jquery.easyui.min.js"></script>
|
|
||||||
|
|
||||||
<script src="https://www.axter.com/js/jquery.prompt.js"></script>
|
|
||||||
<link rel="stylesheet" href="https://www.axter.com/js/jquery.prompt.css"/>
|
|
||||||
<script>
|
|
||||||
var apiKey = "";
|
|
||||||
var GraphQl_URL = "http://localhost:9999/graphql";
|
|
||||||
var OrgPrevPage = null;
|
|
||||||
var OrgNextPage = null;
|
|
||||||
var OrgHomePage = null;
|
|
||||||
var RemoveToKeepConfirmValue = null;
|
|
||||||
var RemoveValidatePromptValue = null;
|
|
||||||
const StrRemoveToKeepConfirm = "RemoveToKeepConfirm=";
|
|
||||||
const StrRemoveValidatePrompt = "RemoveValidatePrompt=";
|
|
||||||
function SetPaginateButtonChange(){
|
|
||||||
var chkBxRemoveValid = document.getElementById("RemoveValidatePrompt");
|
|
||||||
var chkBxDisableDeleteConfirm = document.getElementById("RemoveToKeepConfirm");
|
|
||||||
RemoveToKeepConfirmValue = StrRemoveToKeepConfirm + "false";
|
|
||||||
RemoveValidatePromptValue = StrRemoveValidatePrompt + "false";
|
|
||||||
if (chkBxRemoveValid.checked)
|
|
||||||
RemoveToKeepConfirmValue = StrRemoveToKeepConfirm + "true";
|
|
||||||
if (chkBxDisableDeleteConfirm.checked)
|
|
||||||
RemoveValidatePromptValue = StrRemoveValidatePrompt + "true";
|
|
||||||
document.cookie = RemoveToKeepConfirmValue + "&" + RemoveValidatePromptValue + ";";
|
|
||||||
console.log("Cookies = " + document.cookie);
|
|
||||||
}
|
|
||||||
function trim(str, ch) {
|
|
||||||
var start = 0, end = str.length;
|
|
||||||
while(start < end && str[start] === ch) ++start;
|
|
||||||
while(end > start && str[end - 1] === ch) --end;
|
|
||||||
return (start > 0 || end < str.length) ? str.substring(start, end) : str;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (asyncAjax){
|
|
||||||
$('html').addClass('wait');
|
|
||||||
$("body").css("cursor", "progress");
|
|
||||||
}
|
|
||||||
var chkBxRemoveValid = document.getElementById("RemoveValidatePrompt");
|
|
||||||
if (apiKey !== "")
|
|
||||||
$.ajaxSetup({beforeSend: function(xhr) {xhr.setRequestHeader('apiKey', apiKey);}});
|
|
||||||
$.ajax({method: "POST", url: GraphQl_URL, contentType: "application/json", dataType: "text", cache: asyncAjax, async: asyncAjax,
|
|
||||||
data: JSON.stringify({
|
|
||||||
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);
|
|
||||||
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")))
|
|
||||||
window.location.reload();
|
|
||||||
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){
|
|
||||||
$('html').removeClass('wait');
|
|
||||||
$("body").css("cursor", "default");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function GetStashTabUrl(Tab){
|
|
||||||
var Url = GraphQl_URL;
|
|
||||||
Url = Url.replace("graphql", "settings?tab=" + Tab);
|
|
||||||
console.log("Url = " + Url);
|
|
||||||
return Url;
|
|
||||||
}
|
|
||||||
function SetFlagOnScene(flagType, ActionID){
|
|
||||||
if (flagType === "yellow highlight")
|
|
||||||
$('.ID_' + ActionID).css('background','yellow');
|
|
||||||
else if (flagType === "green highlight")
|
|
||||||
$('.ID_' + ActionID).css('background','#00FF00');
|
|
||||||
else if (flagType === "orange highlight")
|
|
||||||
$('.ID_' + ActionID).css('background','orange');
|
|
||||||
else if (flagType === "cyan highlight")
|
|
||||||
$('.ID_' + ActionID).css('background','cyan');
|
|
||||||
else if (flagType === "pink highlight")
|
|
||||||
$('.ID_' + ActionID).css('background','pink');
|
|
||||||
else if (flagType === "red highlight")
|
|
||||||
$('.ID_' + ActionID).css('background','red');
|
|
||||||
else if (flagType === "strike-through")
|
|
||||||
$('.ID_' + ActionID).css('text-decoration', 'line-through');
|
|
||||||
else if (flagType === "disable-scene")
|
|
||||||
$('.ID_' + ActionID).css({ 'background' : 'gray', 'pointer-events' : 'none' });
|
|
||||||
else if (flagType === "remove all flags")
|
|
||||||
$('.ID_' + ActionID).removeAttr('style'); //.css({ 'background' : '', 'text-decoration' : '', 'pointer-events' : '' });
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
function selectMarker(Mode, ActionID, button){
|
|
||||||
$('<p>Select desire marker type <select><option>yellow highlight</option><option>green highlight</option><option>orange highlight</option><option>cyan highlight</option><option>pink highlight</option><option>red highlight</option><option>strike-through</option><option>disable-scene</option><option>remove all flags</option></select></p>').confirm(function(answer){
|
|
||||||
if(answer.response){
|
|
||||||
console.log("Selected " + $('select',this).val());
|
|
||||||
var flagType = $('select',this).val();
|
|
||||||
if (flagType == null){
|
|
||||||
console.log("Invalid flagType");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!SetFlagOnScene(flagType, ActionID))
|
|
||||||
return;
|
|
||||||
ActionID = ActionID + ":" + flagType;
|
|
||||||
console.log("ActionID = " + ActionID);
|
|
||||||
RunPluginOperation(Mode, ActionID, button, false);
|
|
||||||
}
|
|
||||||
else console.log("Not valid response");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$(document).ready(function(){
|
|
||||||
OrgPrevPage = $("#PrevPage").attr('href');
|
|
||||||
OrgNextPage = $("#NextPage").attr('href');
|
|
||||||
OrgHomePage = $("#HomePage").attr('href');
|
|
||||||
console.log("OrgNextPage = " + OrgNextPage);
|
|
||||||
|
|
||||||
const queryString = window.location.search;
|
|
||||||
const urlParams = new URLSearchParams(queryString);
|
|
||||||
console.log("urlParams = " + urlParams);
|
|
||||||
RemoveToKeepConfirmValue = StrRemoveToKeepConfirm + "false";
|
|
||||||
RemoveValidatePromptValue = StrRemoveValidatePrompt + "false";
|
|
||||||
var FetchCookies = true;
|
|
||||||
if (urlParams.get('RemoveToKeepConfirm') != null && urlParams.get('RemoveToKeepConfirm') !== ""){
|
|
||||||
FetchCookies = false;
|
|
||||||
RemoveToKeepConfirmValue = StrRemoveToKeepConfirm + urlParams.get('RemoveToKeepConfirm');
|
|
||||||
if (urlParams.get('RemoveToKeepConfirm') === "true")
|
|
||||||
$( "#RemoveToKeepConfirm" ).prop("checked", true);
|
|
||||||
else
|
|
||||||
$( "#RemoveToKeepConfirm" ).prop("checked", false);
|
|
||||||
}
|
|
||||||
if (urlParams.get('RemoveValidatePrompt') != null && urlParams.get('RemoveValidatePrompt') !== ""){
|
|
||||||
FetchCookies = false;
|
|
||||||
RemoveValidatePromptValue = StrRemoveValidatePrompt + urlParams.get('RemoveValidatePrompt');
|
|
||||||
console.log("RemoveValidatePromptValue = " + RemoveValidatePromptValue);
|
|
||||||
if (urlParams.get('RemoveValidatePrompt') === "true")
|
|
||||||
$( "#RemoveValidatePrompt" ).prop("checked", true);
|
|
||||||
else
|
|
||||||
$( "#RemoveValidatePrompt" ).prop("checked", false);
|
|
||||||
}
|
|
||||||
if (FetchCookies){
|
|
||||||
console.log("Cookies = " + document.cookie);
|
|
||||||
var cookies = document.cookie;
|
|
||||||
if (cookies.indexOf(StrRemoveToKeepConfirm) > -1){
|
|
||||||
var idx = cookies.indexOf(StrRemoveToKeepConfirm) + StrRemoveToKeepConfirm.length;
|
|
||||||
var s = cookies.substring(idx);
|
|
||||||
console.log("StrRemoveToKeepConfirm Cookie = " + s);
|
|
||||||
if (s.startsWith("true"))
|
|
||||||
$( "#RemoveToKeepConfirm" ).prop("checked", true);
|
|
||||||
else
|
|
||||||
$( "#RemoveToKeepConfirm" ).prop("checked", false);
|
|
||||||
}
|
|
||||||
if (cookies.indexOf(StrRemoveValidatePrompt) > -1){
|
|
||||||
var idx = cookies.indexOf(StrRemoveValidatePrompt) + StrRemoveValidatePrompt.length;
|
|
||||||
var s = cookies.substring(idx);
|
|
||||||
console.log("StrRemoveValidatePrompt Cookie = " + s);
|
|
||||||
if (s.startsWith("true"))
|
|
||||||
$( "#RemoveValidatePrompt" ).prop("checked", true);
|
|
||||||
else
|
|
||||||
$( "#RemoveValidatePrompt" ).prop("checked", false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SetPaginateButtonChange();
|
|
||||||
function ProcessClick(This_){
|
|
||||||
if (This_ == null)
|
|
||||||
return;
|
|
||||||
const ID = This_.id;
|
|
||||||
var Value = This_.getAttribute("value");
|
|
||||||
if ((ID == null || ID === "") && (Value == null || Value === ""))
|
|
||||||
return;
|
|
||||||
if (Value == null) Value = "";
|
|
||||||
var Mode = Value;
|
|
||||||
var ActionID = ID;
|
|
||||||
console.log("Mode = " + Mode + "; ActionID =" + ActionID);
|
|
||||||
if (Mode === "DoNothing")
|
|
||||||
return;
|
|
||||||
if (ActionID === "AdvanceMenu" || ActionID === "AdvanceMenu_")
|
|
||||||
{
|
|
||||||
var newUrl = window.location.href;
|
|
||||||
newUrl = newUrl.replace(/report\/DuplicateTagScenes[_0-9]*.html/g, "advance_options.html?GQL=" + GraphQl_URL + "&apiKey=" + apiKey);
|
|
||||||
window.open(newUrl, "_blank");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Mode.startsWith("deleteScene") || Mode === "removeScene"){
|
|
||||||
var chkBxDisableDeleteConfirm = document.getElementById("RemoveToKeepConfirm");
|
|
||||||
question = "Are you sure you want to delete this file and remove scene from stash?";
|
|
||||||
if (Mode !== "deleteScene" && Mode.startsWith("deleteScene")) question = "Are you sure you want to delete all the flagged files and remove them from stash?";
|
|
||||||
if (Mode === "removeScene") question = "Are you sure you want to remove scene from stash?";
|
|
||||||
if (!chkBxDisableDeleteConfirm.checked && !confirm(question))
|
|
||||||
return;
|
|
||||||
if (Mode === "deleteScene" || Mode === "removeScene"){
|
|
||||||
$('.ID_' + ActionID).css('background-color','gray');
|
|
||||||
$('.ID_' + ActionID).css('pointer-events','none');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ID === "viewStashPlugin")
|
|
||||||
window.open(GetStashTabUrl("plugins"), "_blank");
|
|
||||||
else if (ID === "viewStashTools")
|
|
||||||
window.open(GetStashTabUrl("tools"), "_blank");
|
|
||||||
else if (Mode === "newName" || Mode === "renameFile"){
|
|
||||||
var myArray = ActionID.split(":");
|
|
||||||
var promptStr = "Enter new name for scene ID " + myArray[0] + ", or press escape to cancel.";
|
|
||||||
if (Mode === "renameFile")
|
|
||||||
promptStr = "Press enter to rename scene ID " + myArray[0] + ", or press escape to cancel.";
|
|
||||||
var newName=prompt(promptStr,trim(myArray[1], "'"));
|
|
||||||
if (newName === null)
|
|
||||||
return;
|
|
||||||
ActionID = myArray[0] + ":" + newName;
|
|
||||||
Mode = "renameFile";
|
|
||||||
}
|
|
||||||
else if (Mode === "flagScene"){
|
|
||||||
selectMarker(Mode, ActionID, This_);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (Mode.startsWith("flagScene")){
|
|
||||||
var flagType = Mode.substring(9);
|
|
||||||
Mode = "flagScene";
|
|
||||||
if (!SetFlagOnScene(flagType, ActionID))
|
|
||||||
return;
|
|
||||||
ActionID = ActionID + ":" + flagType;
|
|
||||||
console.log("ActionID = " + ActionID);
|
|
||||||
}
|
|
||||||
RunPluginOperation(Mode, ActionID, This_, true);
|
|
||||||
}
|
|
||||||
$("button").click(function(){
|
|
||||||
ProcessClick(this);
|
|
||||||
});
|
|
||||||
$("a").click(function(){
|
|
||||||
if (this.id.startsWith("btn_mnu"))
|
|
||||||
return;
|
|
||||||
if (this.id === "reload"){
|
|
||||||
window.location.reload();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.id === "PrevPage" || this.id === "NextPage" || this.id === "HomePage" || this.id === "PrevPage_Top" || this.id === "NextPage_Top" || this.id === "HomePage_Top"){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ProcessClick(this);
|
|
||||||
});
|
|
||||||
$("div").click(function(){
|
|
||||||
if (this.id.startsWith("btn_mnu"))
|
|
||||||
return;
|
|
||||||
if (this.id === "reload"){
|
|
||||||
window.location.reload();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ProcessClick(this);
|
|
||||||
});
|
|
||||||
$("#RemoveValidatePrompt").change(function() {
|
|
||||||
console.log("checkbox clicked");
|
|
||||||
SetPaginateButtonChange();
|
|
||||||
});
|
|
||||||
$("#RemoveToKeepConfirm").change(function() {
|
|
||||||
SetPaginateButtonChange();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div style="background-color:BackgroundColorPlaceHolder;color:TextColorPlaceHolder;">
|
|
||||||
<center><table style="color:darkgreen;background-color:powderblue;">
|
|
||||||
<tr><th>Report Info</th><th>Report Options</th></tr>
|
|
||||||
<tr>
|
|
||||||
<td><table><tr>
|
|
||||||
<td>Found (QtyPlaceHolder) duplice sets</td>
|
|
||||||
<td>Date Created: (DateCreatedPlaceHolder)</td>
|
|
||||||
</tr></table></td>
|
|
||||||
<td><table><tr>
|
|
||||||
<td>
|
|
||||||
<div class="easyui-panel">
|
|
||||||
<a id="btn_mnu" class="easyui-menubutton" menu="#btn_mnu1">Menu</a>
|
|
||||||
</div>
|
|
||||||
<div id="btn_mnu1">
|
|
||||||
<div iconCls="icon-add" id="AdvanceMenu" title="Open [Advance Duplicate File Deletion Menu] on a new tab in the browser." name="AdvanceMenu">Advance Duplicate File Deletion Menu</div>
|
|
||||||
<div iconCls="icon-reload" id="reload" title="Reload (refresh) this page." name="reload">Reload Page</div>
|
|
||||||
<div iconCls="icon-menu1" id="viewStashPlugin" title="View Stash plugins menu.">Stash Plugins</div>
|
|
||||||
<div iconCls="icon-menu-blue" id="viewStashTools" title="View Stash tools menu.">Stash Tools</div>
|
|
||||||
<div iconCls="icon-more"><a href="https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins" target="_blank" rel="noopener noreferrer">Axter-Stash Plugins</a></div>
|
|
||||||
<div class="menu-sep"></div>
|
|
||||||
<div iconCls="icon-merge" id="mergeMetadataForAll" value="mergeTags" title="Merge scene metadata from [Duplicate to Delete] to [Duplicate to Keep] for any [Duplicate to Keep] scene missing metadata that is in associated [Duplicate to Delete] scene. This action make take a few minutes to complete.">Merge Tags, Performers, and Galleries</button></div>
|
|
||||||
<div iconCls="icon-no" id="clear_duplicate_tags_task" value="clear_duplicate_tags_task" title="Remove duplicate (_DuplicateMarkForDeletion_?) tag from all scenes. This action make take a few minutes to complete.">Clear Dup (_DuplicateMarkForDeletion_) Tags</button></div>
|
|
||||||
<div class="menu-sep"></div>
|
|
||||||
<div iconCls="icon-pink-x" id="fileNotExistToDelete" value="Tagged" title="Delete tagged duplicates for which file does NOT exist.">Delete Dup Tagged Files That do Not Exist</button></div>
|
|
||||||
<div iconCls="icon-cancel" id="fileNotExistToDelete" value="Report" title="Delete duplicate candidate files in report for which file does NOT exist.">Delete Files That do Not Exist in Report</button></div>
|
|
||||||
<div class="menu-sep"></div>
|
|
||||||
<div iconCls="icon-cancel" title="Delete all [Duplicate to Delete] scenes flagged with selected flag.">
|
|
||||||
<span>Delete Flagged Scenes</span>
|
|
||||||
<div>
|
|
||||||
<div iconCls="icon-cancel" title="Delete all [Duplicate to Delete] cyan flagged scenes in report." value="deleteSceneCyanFlag" id="cyan" style="background-color:cyan;color:black;" >Delete All Cyan Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-cancel" title="Delete all [Duplicate to Delete] green flagged scenes in report." value="deleteSceneGreenFlag" id="green" style="background-color:#00FF00;color:black;" >Delete All Green Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-cancel" title="Delete all [Duplicate to Delete] orange flagged scenes in report." value="deleteSceneOrangeFlag" id="orange" style="background-color:orange;color:black;" >Delete All Orange Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-cancel" title="Delete all [Duplicate to Delete] yellow flagged scenes in report." value="deleteSceneYellowFlag" id="yellow" style="background-color:yellow;color:black;" >Delete All Yellow Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-cancel" title="Delete all [Duplicate to Delete] pink flagged scenes in report." value="deleteScenePinkFlag" id="pink" style="background-color:pink;color:black;" >Delete All Pink Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-cancel" title="Delete all [Duplicate to Delete] red flagged scenes in report." value="deleteSceneRedFlag" id="red" style="background-color:red;color:white;" >Delete All Red Flagged Scenes</button></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div iconCls="icon-copy" title="Copy the file from [Duplicate to Delete] to [Duplicate to Keep] for all [Duplicate to Delete] flagged scenes.">
|
|
||||||
<span>Copy Flagged Scenes</span>
|
|
||||||
<div>
|
|
||||||
<div iconCls="icon-copy-clear" title="Copy all cyan flagged scenes in report." value="copySceneCyanFlag" id="cyan" style="background-color:cyan;color:black;" >Copy All Cyan Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-copy-clear" title="Copy all green flagged scenes in report." value="copySceneGreenFlag" id="green" style="background-color:#00FF00;color:black;" >Copy All Green Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-copy-clear" title="Copy all orange flagged scenes in report." value="copySceneOrangeFlag" id="orange" style="background-color:orange;color:black;" >Copy All Orange Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-copy-clear" title="Copy all yellow flagged scenes in report." value="copySceneYellowFlag" id="yellow" style="background-color:yellow;color:black;" >Copy All Yellow Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-copy-clear" title="Copy all pink flagged scenes in report." value="copyScenePinkFlag" id="pink" style="background-color:pink;color:black;" >Copy All Pink Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-copy-clear" title="Copy all red flagged scenes in report." value="copySceneRedFlag" id="red" style="background-color:red;color:white;" >Copy All Red Flagged Scenes</button></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div iconCls="icon-documents" title="Copy the file and metadata (Tags, Performers, & Galleries) from [Duplicate to Delete] to [Duplicate to Keep] for all [Duplicate to Delete] flagged scenes.">
|
|
||||||
<span>Move Flagged Scenes</span>
|
|
||||||
<div>
|
|
||||||
<div iconCls="icon-documents" title="Move all cyan flagged scenes in report." value="moveSceneCyanFlag" id="cyan" style="background-color:cyan;color:black;" >Move All Cyan Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-documents" title="Move all green flagged scenes in report." value="moveSceneGreenFlag" id="green" style="background-color:#00FF00;color:black;" >Move All Green Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-documents" title="Move all orange flagged scenes in report." value="moveSceneOrangeFlag" id="orange" style="background-color:orange;color:black;" >Move All Orange Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-documents" title="Move all yellow flagged scenes in report." value="moveSceneYellowFlag" id="yellow" style="background-color:yellow;color:black;" >Move All Yellow Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-documents" title="Move all pink flagged scenes in report." value="moveScenePinkFlag" id="pink" style="background-color:pink;color:black;" >Move All Pink Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-documents" title="Move all red flagged scenes in report." value="moveSceneRedFlag" id="red" style="background-color:red;color:white;" >Move All Red Flagged Scenes</button></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div iconCls="icon-merge" title="Merge scene metadata from [Duplicate to Delete] to [Duplicate to Keep] for all [Duplicate to Delete] flagged scenes. This action make take a few minutes to complete.">
|
|
||||||
<span>Merge (Tags, Performers, & Galleries) Flagged Scenes</span>
|
|
||||||
<div>
|
|
||||||
<div iconCls="icon-merge" title="Merge all cyan flagged scenes in report." value="mergeSceneCyanFlag" id="cyan" style="background-color:cyan;color:black;" >Merge All Cyan Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-merge" title="Merge all green flagged scenes in report." value="mergeSceneGreenFlag" id="green" style="background-color:#00FF00;color:black;" >Merge All Green Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-merge" title="Merge all orange flagged scenes in report." value="mergeSceneOrangeFlag" id="orange" style="background-color:orange;color:black;" >Merge All Orange Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-merge" title="Merge all yellow flagged scenes in report." value="mergeSceneYellowFlag" id="yellow" style="background-color:yellow;color:black;" >Merge All Yellow Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-merge" title="Merge all pink flagged scenes in report." value="mergeScenePinkFlag" id="pink" style="background-color:pink;color:black;" >Merge All Pink Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-merge" title="Merge all red flagged scenes in report." value="mergeSceneRedFlag" id="red" style="background-color:red;color:white;" >Merge All Red Flagged Scenes</button></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div iconCls="icon-lock" title="Add special tag [_ExcludeDuplicateMarkForDeletion] for [Duplicate to Delete] scenes flagged with selected flag.">
|
|
||||||
<span>Add Exclude TAG to Flagged Scenes</span>
|
|
||||||
<div>
|
|
||||||
<div iconCls="icon-lock" title="Add Exclude TAG to all [Duplicate to Delete] cyan flagged scenes in report." value="addExcludeTagCyanFlag" id="cyan" style="background-color:cyan;color:black;" >Add Exclude TAG to Cyan Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-lock" title="Add Exclude TAG to all [Duplicate to Delete] green flagged scenes in report." value="addExcludeTagGreenFlag" id="green" style="background-color:#00FF00;color:black;" >Add Exclude TAG to Green Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-lock" title="Add Exclude TAG to all [Duplicate to Delete] orange flagged scenes in report." value="addExcludeTagOrangeFlag" id="orange" style="background-color:orange;color:black;" >Add Exclude TAG to Orange Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-lock" title="Add Exclude TAG to all [Duplicate to Delete] yellow flagged scenes in report." value="addExcludeTagYellowFlag" id="yellow" style="background-color:yellow;color:black;" >Add Exclude TAG to Yellow Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-lock" title="Add Exclude TAG to all [Duplicate to Delete] pink flagged scenes in report." value="addExcludeTagPinkFlag" id="pink" style="background-color:pink;color:black;" >Add Exclude TAG to Pink Flagged Scenes</button></div>
|
|
||||||
<div iconCls="icon-lock" title="Add Exclude TAG to all [Duplicate to Delete] red flagged scenes in report." value="addExcludeTagRedFlag" id="red" style="background-color:red;color:white;" >Add Exclude TAG to Red Flagged Scenes</button></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="menu-sep"></div>
|
|
||||||
<div iconCls="icon-eraser-minus" id="clearAllSceneFlags" value="clearAllSceneFlags" title="Remove all flags from report for all scenes, except for deletion flag.">Clear All Flags from All Scenes</button></div>
|
|
||||||
<div iconCls="icon-eraser-minus" class="easyui-tooltip" title="Clear specific flag from all scenes.">
|
|
||||||
<span>Clear Flag from All Scenes</span>
|
|
||||||
<div>
|
|
||||||
<div iconCls="icon-eraser-minus" title="Clear flag cyan from all scenes." value="clearFlagCyanFlag" id="cyan" style="background-color:cyan;color:black;" >Clear Cyan</button></div>
|
|
||||||
<div iconCls="icon-eraser-minus" title="Clear flag green from all scenes." value="clearFlagGreenFlag" id="green" style="background-color:#00FF00;color:black;" >Clear Green</button></div>
|
|
||||||
<div iconCls="icon-eraser-minus" title="Clear flag orange from all scenes." value="clearFlagOrangeFlag" id="orange" style="background-color:orange;color:black;" >Clear Orange</button></div>
|
|
||||||
<div iconCls="icon-eraser-minus" title="Clear flag yellow from all scenes." value="clearFlagYellowFlag" id="yellow" style="background-color:yellow;color:black;" >Clear Yellow</button></div>
|
|
||||||
<div iconCls="icon-eraser-minus" title="Clear flag pink from all scenes." value="clearFlagPinkFlag" id="pink" style="background-color:pink;color:black;" >Clear Pink</button></div>
|
|
||||||
<div iconCls="icon-eraser-minus" title="Clear flag red from all scenes." value="clearFlagRedFlag" id="red" style="background-color:red;color:white;" >Clear Red</button></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td><input type="checkbox" id="RemoveValidatePrompt" name="RemoveValidatePrompt"><label for="RemoveValidatePrompt" title="Disable notice for task completion (Popup).">Disable Complete Confirmation</label><br></td>
|
|
||||||
<td><input type="checkbox" id="RemoveToKeepConfirm" name="RemoveToKeepConfirm"><label for="RemoveToKeepConfirm" title="Disable confirmation prompts for delete scenes">Disable Delete Confirmation</label><br></td>
|
|
||||||
|
|
||||||
</tr></table></td>
|
|
||||||
</tr></table></center>
|
|
||||||
<h2>Stash Duplicate Scenes Report (MatchTypePlaceHolder)</h2>\n""",
|
|
||||||
# HTML report postfiox, after table listing
|
# HTML report postfiox, after table listing
|
||||||
"htmlReportPostfix" : "\n</div></body></html>",
|
"htmlReportPostfix" : "\n</div></body></html>",
|
||||||
# HTML report table
|
# HTML report table
|
||||||
|
|||||||
403
plugins/DupFileManager/DupFileManager_report_header
Normal file
403
plugins/DupFileManager/DupFileManager_report_header
Normal file
@@ -0,0 +1,403 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Stash Duplicate Report</title>
|
||||||
|
<style>
|
||||||
|
h2 {text-align: center;}
|
||||||
|
table, th, td {border:1px solid black;}
|
||||||
|
.inline {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.scene-details{text-align: center;font-size: small;}
|
||||||
|
.reason-details{text-align: left;font-size: small;}
|
||||||
|
.link-items{text-align: center;font-size: small;}
|
||||||
|
ul {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 1px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.large {
|
||||||
|
position: absolute;
|
||||||
|
left: -9999px;
|
||||||
|
}
|
||||||
|
li:hover .large {
|
||||||
|
left: 20px;
|
||||||
|
top: -150px;
|
||||||
|
}
|
||||||
|
.large-image {
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 1px 1px 3px 3px rgba(127, 127, 127, 0.15);;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="https://axter.com/js/easyui/themes/black/easyui.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="https://axter.com/js/easyui/themes/icon.css">
|
||||||
|
<script type="text/javascript" src="https://axter.com/js/jquery-3.7.1.min.js"></script>
|
||||||
|
<script type="text/javascript" src="https://axter.com/js/easyui/jquery.easyui.min.js"></script>
|
||||||
|
|
||||||
|
<script src="https://www.axter.com/js/jquery.prompt.js"></script>
|
||||||
|
<link rel="stylesheet" href="https://www.axter.com/js/jquery.prompt.css"/>
|
||||||
|
<script>
|
||||||
|
var apiKey = "";
|
||||||
|
var GraphQl_URL = "http://localhost:9999/graphql";
|
||||||
|
var OrgPrevPage = null;
|
||||||
|
var OrgNextPage = null;
|
||||||
|
var OrgHomePage = null;
|
||||||
|
var RemoveToKeepConfirmValue = null;
|
||||||
|
var RemoveValidatePromptValue = null;
|
||||||
|
console.log("Cookies = " + document.cookie);
|
||||||
|
const StrRemoveToKeepConfirm = "RemoveToKeepConfirm=";
|
||||||
|
const StrRemoveValidatePrompt = "RemoveValidatePrompt=";
|
||||||
|
function SetPaginateButtonChange(){
|
||||||
|
var chkBxRemoveValid = document.getElementById("RemoveValidatePrompt");
|
||||||
|
var chkBxDisableDeleteConfirm = document.getElementById("RemoveToKeepConfirm");
|
||||||
|
RemoveToKeepConfirmValue = StrRemoveToKeepConfirm + "false";
|
||||||
|
RemoveValidatePromptValue = StrRemoveValidatePrompt + "false";
|
||||||
|
if (chkBxRemoveValid.checked)
|
||||||
|
RemoveToKeepConfirmValue = StrRemoveToKeepConfirm + "true";
|
||||||
|
if (chkBxDisableDeleteConfirm.checked)
|
||||||
|
RemoveValidatePromptValue = StrRemoveValidatePrompt + "true";
|
||||||
|
document.cookie = RemoveToKeepConfirmValue + "&" + RemoveValidatePromptValue + ";";
|
||||||
|
console.log("Cookies = " + document.cookie);
|
||||||
|
}
|
||||||
|
function trim(str, ch) {
|
||||||
|
var start = 0, end = str.length;
|
||||||
|
while(start < end && str[start] === ch) ++start;
|
||||||
|
while(end > start && str[end - 1] === ch) --end;
|
||||||
|
return (start > 0 || end < str.length) ? str.substring(start, end) : str;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (asyncAjax){
|
||||||
|
$('html').addClass('wait');
|
||||||
|
$("body").css("cursor", "progress");
|
||||||
|
}
|
||||||
|
var chkBxRemoveValid = document.getElementById("RemoveValidatePrompt");
|
||||||
|
if (apiKey !== "")
|
||||||
|
$.ajaxSetup({beforeSend: function(xhr) {xhr.setRequestHeader('apiKey', apiKey);}});
|
||||||
|
$.ajax({method: "POST", url: GraphQl_URL, contentType: "application/json", dataType: "text", cache: asyncAjax, async: asyncAjax,
|
||||||
|
data: JSON.stringify({
|
||||||
|
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);
|
||||||
|
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")))
|
||||||
|
window.location.reload();
|
||||||
|
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){
|
||||||
|
$('html').removeClass('wait');
|
||||||
|
$("body").css("cursor", "default");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function GetStashTabUrl(Tab){
|
||||||
|
var Url = GraphQl_URL;
|
||||||
|
Url = Url.replace("graphql", "settings?tab=" + Tab);
|
||||||
|
console.log("Url = " + Url);
|
||||||
|
return Url;
|
||||||
|
}
|
||||||
|
function SetFlagOnScene(flagType, ActionID){
|
||||||
|
if (flagType === "yellow highlight")
|
||||||
|
$('.ID_' + ActionID).css('background','yellow');
|
||||||
|
else if (flagType === "green highlight")
|
||||||
|
$('.ID_' + ActionID).css('background','#00FF00');
|
||||||
|
else if (flagType === "orange highlight")
|
||||||
|
$('.ID_' + ActionID).css('background','orange');
|
||||||
|
else if (flagType === "cyan highlight")
|
||||||
|
$('.ID_' + ActionID).css('background','cyan');
|
||||||
|
else if (flagType === "pink highlight")
|
||||||
|
$('.ID_' + ActionID).css('background','pink');
|
||||||
|
else if (flagType === "red highlight")
|
||||||
|
$('.ID_' + ActionID).css('background','red');
|
||||||
|
else if (flagType === "strike-through")
|
||||||
|
$('.ID_' + ActionID).css('text-decoration', 'line-through');
|
||||||
|
else if (flagType === "disable-scene")
|
||||||
|
$('.ID_' + ActionID).css({ 'background' : 'gray', 'pointer-events' : 'none' });
|
||||||
|
else if (flagType === "remove all flags")
|
||||||
|
$('.ID_' + ActionID).removeAttr('style'); //.css({ 'background' : '', 'text-decoration' : '', 'pointer-events' : '' });
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function selectMarker(Mode, ActionID, button){
|
||||||
|
$('<p>Select desire marker type <select><option>yellow highlight</option><option>green highlight</option><option>orange highlight</option><option>cyan highlight</option><option>pink highlight</option><option>red highlight</option><option>strike-through</option><option>disable-scene</option><option>remove all flags</option></select></p>').confirm(function(answer){
|
||||||
|
if(answer.response){
|
||||||
|
console.log("Selected " + $('select',this).val());
|
||||||
|
var flagType = $('select',this).val();
|
||||||
|
if (flagType == null){
|
||||||
|
console.log("Invalid flagType");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!SetFlagOnScene(flagType, ActionID))
|
||||||
|
return;
|
||||||
|
ActionID = ActionID + ":" + flagType;
|
||||||
|
console.log("ActionID = " + ActionID);
|
||||||
|
RunPluginOperation(Mode, ActionID, button, false);
|
||||||
|
}
|
||||||
|
else console.log("Not valid response");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$(document).ready(function(){
|
||||||
|
OrgPrevPage = $("#PrevPage").attr('href');
|
||||||
|
OrgNextPage = $("#NextPage").attr('href');
|
||||||
|
OrgHomePage = $("#HomePage").attr('href');
|
||||||
|
console.log("OrgNextPage = " + OrgNextPage);
|
||||||
|
|
||||||
|
const queryString = window.location.search;
|
||||||
|
const urlParams = new URLSearchParams(queryString);
|
||||||
|
console.log("urlParams = " + urlParams);
|
||||||
|
RemoveToKeepConfirmValue = StrRemoveToKeepConfirm + "false";
|
||||||
|
RemoveValidatePromptValue = StrRemoveValidatePrompt + "false";
|
||||||
|
var FetchCookies = true;
|
||||||
|
if (urlParams.get('RemoveToKeepConfirm') != null && urlParams.get('RemoveToKeepConfirm') !== ""){
|
||||||
|
FetchCookies = false;
|
||||||
|
RemoveToKeepConfirmValue = StrRemoveToKeepConfirm + urlParams.get('RemoveToKeepConfirm');
|
||||||
|
if (urlParams.get('RemoveToKeepConfirm') === "true")
|
||||||
|
$( "#RemoveToKeepConfirm" ).prop("checked", true);
|
||||||
|
else
|
||||||
|
$( "#RemoveToKeepConfirm" ).prop("checked", false);
|
||||||
|
}
|
||||||
|
if (urlParams.get('RemoveValidatePrompt') != null && urlParams.get('RemoveValidatePrompt') !== ""){
|
||||||
|
FetchCookies = false;
|
||||||
|
RemoveValidatePromptValue = StrRemoveValidatePrompt + urlParams.get('RemoveValidatePrompt');
|
||||||
|
console.log("RemoveValidatePromptValue = " + RemoveValidatePromptValue);
|
||||||
|
if (urlParams.get('RemoveValidatePrompt') === "true")
|
||||||
|
$( "#RemoveValidatePrompt" ).prop("checked", true);
|
||||||
|
else
|
||||||
|
$( "#RemoveValidatePrompt" ).prop("checked", false);
|
||||||
|
}
|
||||||
|
if (FetchCookies){
|
||||||
|
console.log("Cookies = " + document.cookie);
|
||||||
|
var cookies = document.cookie;
|
||||||
|
if (cookies.indexOf(StrRemoveToKeepConfirm) > -1){
|
||||||
|
var idx = cookies.indexOf(StrRemoveToKeepConfirm) + StrRemoveToKeepConfirm.length;
|
||||||
|
var s = cookies.substring(idx);
|
||||||
|
console.log("StrRemoveToKeepConfirm Cookie = " + s);
|
||||||
|
if (s.startsWith("true"))
|
||||||
|
$( "#RemoveToKeepConfirm" ).prop("checked", true);
|
||||||
|
else
|
||||||
|
$( "#RemoveToKeepConfirm" ).prop("checked", false);
|
||||||
|
}
|
||||||
|
if (cookies.indexOf(StrRemoveValidatePrompt) > -1){
|
||||||
|
var idx = cookies.indexOf(StrRemoveValidatePrompt) + StrRemoveValidatePrompt.length;
|
||||||
|
var s = cookies.substring(idx);
|
||||||
|
console.log("StrRemoveValidatePrompt Cookie = " + s);
|
||||||
|
if (s.startsWith("true"))
|
||||||
|
$( "#RemoveValidatePrompt" ).prop("checked", true);
|
||||||
|
else
|
||||||
|
$( "#RemoveValidatePrompt" ).prop("checked", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetPaginateButtonChange();
|
||||||
|
function ProcessClick(This_){
|
||||||
|
if (This_ == null)
|
||||||
|
return;
|
||||||
|
const ID = This_.id;
|
||||||
|
var Value = This_.getAttribute("value");
|
||||||
|
if ((ID == null || ID === "") && (Value == null || Value === ""))
|
||||||
|
return;
|
||||||
|
if (Value == null) Value = "";
|
||||||
|
var Mode = Value;
|
||||||
|
var ActionID = ID;
|
||||||
|
console.log("Mode = " + Mode + "; ActionID =" + ActionID);
|
||||||
|
if (Mode === "DoNothing")
|
||||||
|
return;
|
||||||
|
if (ActionID === "AdvanceMenu" || ActionID === "AdvanceMenu_")
|
||||||
|
{
|
||||||
|
var newUrl = window.location.href;
|
||||||
|
newUrl = newUrl.replace(/report\/DuplicateTagScenes[_0-9]*.html/g, "advance_options.html?GQL=" + GraphQl_URL + "&apiKey=" + apiKey);
|
||||||
|
window.open(newUrl, "_blank");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Mode.startsWith("deleteScene") || Mode === "removeScene"){
|
||||||
|
var chkBxDisableDeleteConfirm = document.getElementById("RemoveToKeepConfirm");
|
||||||
|
question = "Are you sure you want to delete this file and remove scene from stash?";
|
||||||
|
if (Mode !== "deleteScene" && Mode.startsWith("deleteScene")) question = "Are you sure you want to delete all the flagged files and remove them from stash?";
|
||||||
|
if (Mode === "removeScene") question = "Are you sure you want to remove scene from stash?";
|
||||||
|
if (!chkBxDisableDeleteConfirm.checked && !confirm(question))
|
||||||
|
return;
|
||||||
|
if (Mode === "deleteScene" || Mode === "removeScene"){
|
||||||
|
$('.ID_' + ActionID).css('background-color','gray');
|
||||||
|
$('.ID_' + ActionID).css('pointer-events','none');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ID === "viewStashPlugin")
|
||||||
|
window.open(GetStashTabUrl("plugins"), "_blank");
|
||||||
|
else if (ID === "viewStashTools")
|
||||||
|
window.open(GetStashTabUrl("tools"), "_blank");
|
||||||
|
else if (Mode === "newName" || Mode === "renameFile"){
|
||||||
|
var myArray = ActionID.split(":");
|
||||||
|
var promptStr = "Enter new name for scene ID " + myArray[0] + ", or press escape to cancel.";
|
||||||
|
if (Mode === "renameFile")
|
||||||
|
promptStr = "Press enter to rename scene ID " + myArray[0] + ", or press escape to cancel.";
|
||||||
|
var newName=prompt(promptStr,trim(myArray[1], "'"));
|
||||||
|
if (newName === null)
|
||||||
|
return;
|
||||||
|
ActionID = myArray[0] + ":" + newName;
|
||||||
|
Mode = "renameFile";
|
||||||
|
}
|
||||||
|
else if (Mode === "flagScene"){
|
||||||
|
selectMarker(Mode, ActionID, This_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (Mode.startsWith("flagScene")){
|
||||||
|
var flagType = Mode.substring(9);
|
||||||
|
Mode = "flagScene";
|
||||||
|
if (!SetFlagOnScene(flagType, ActionID))
|
||||||
|
return;
|
||||||
|
ActionID = ActionID + ":" + flagType;
|
||||||
|
console.log("ActionID = " + ActionID);
|
||||||
|
}
|
||||||
|
RunPluginOperation(Mode, ActionID, This_, true);
|
||||||
|
}
|
||||||
|
$("button").click(function(){
|
||||||
|
ProcessClick(this);
|
||||||
|
});
|
||||||
|
$("a").click(function(){
|
||||||
|
if (this.id.startsWith("btn_mnu"))
|
||||||
|
return;
|
||||||
|
if (this.id === "reload"){
|
||||||
|
window.location.reload();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.id === "PrevPage" || this.id === "NextPage" || this.id === "HomePage" || this.id === "PrevPage_Top" || this.id === "NextPage_Top" || this.id === "HomePage_Top"){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ProcessClick(this);
|
||||||
|
});
|
||||||
|
$("div").click(function(){
|
||||||
|
if (this.id.startsWith("btn_mnu"))
|
||||||
|
return;
|
||||||
|
if (this.id === "reload"){
|
||||||
|
window.location.reload();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ProcessClick(this);
|
||||||
|
});
|
||||||
|
$("#RemoveValidatePrompt").change(function() {
|
||||||
|
console.log("checkbox clicked");
|
||||||
|
SetPaginateButtonChange();
|
||||||
|
});
|
||||||
|
$("#RemoveToKeepConfirm").change(function() {
|
||||||
|
SetPaginateButtonChange();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div style="background-color:BackgroundColorPlaceHolder;color:TextColorPlaceHolder;">
|
||||||
|
<center><table style="color:darkgreen;background-color:powderblue;">
|
||||||
|
<tr><th>Report Info</th><th>Report Options</th></tr>
|
||||||
|
<tr>
|
||||||
|
<td><table><tr>
|
||||||
|
<td>Found (QtyPlaceHolder) duplice sets</td>
|
||||||
|
<td>Date Created: (DateCreatedPlaceHolder)</td>
|
||||||
|
</tr></table></td>
|
||||||
|
<td><table><tr>
|
||||||
|
<td>
|
||||||
|
<div class="easyui-panel">
|
||||||
|
<a id="btn_mnu" class="easyui-menubutton" menu="#btn_mnu1">Menu</a>
|
||||||
|
</div>
|
||||||
|
<div id="btn_mnu1">
|
||||||
|
<div iconCls="icon-add" id="AdvanceMenu" title="Open [Advance Duplicate File Deletion Menu] on a new tab in the browser." name="AdvanceMenu">Advance Duplicate File Deletion Menu</div>
|
||||||
|
<div iconCls="icon-reload" id="reload" title="Reload (refresh) this page." name="reload">Reload Page</div>
|
||||||
|
<div iconCls="icon-menu1" id="viewStashPlugin" title="View Stash plugins menu.">Stash Plugins</div>
|
||||||
|
<div iconCls="icon-menu-blue" id="viewStashTools" title="View Stash tools menu.">Stash Tools</div>
|
||||||
|
<div iconCls="icon-more"><a href="https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins" target="_blank" rel="noopener noreferrer">Axter-Stash Plugins</a></div>
|
||||||
|
<div class="menu-sep"></div>
|
||||||
|
<div iconCls="icon-merge" id="mergeMetadataForAll" value="mergeTags" title="Merge scene metadata from [Duplicate to Delete] to [Duplicate to Keep] for any [Duplicate to Keep] scene missing metadata that is in associated [Duplicate to Delete] scene. This action make take a few minutes to complete.">Merge Tags, Performers, and Galleries</button></div>
|
||||||
|
<div iconCls="icon-no" id="clear_duplicate_tags_task" value="clear_duplicate_tags_task" title="Remove duplicate (_DuplicateMarkForDeletion_?) tag from all scenes. This action make take a few minutes to complete.">Clear Dup (_DuplicateMarkForDeletion_) Tags</button></div>
|
||||||
|
<div class="menu-sep"></div>
|
||||||
|
<div iconCls="icon-pink-x" id="fileNotExistToDelete" value="Tagged" title="Delete tagged duplicates for which file does NOT exist.">Delete Dup Tagged Files That do Not Exist</button></div>
|
||||||
|
<div iconCls="icon-cancel" id="fileNotExistToDelete" value="Report" title="Delete duplicate candidate files in report for which file does NOT exist.">Delete Files That do Not Exist in Report</button></div>
|
||||||
|
<div class="menu-sep"></div>
|
||||||
|
<div iconCls="icon-cancel" title="Delete all [Duplicate to Delete] scenes flagged with selected flag.">
|
||||||
|
<span>Delete Flagged Scenes</span>
|
||||||
|
<div>
|
||||||
|
<div iconCls="icon-cancel" title="Delete all [Duplicate to Delete] cyan flagged scenes in report." value="deleteSceneCyanFlag" id="cyan" style="background-color:cyan;color:black;" >Delete All Cyan Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-cancel" title="Delete all [Duplicate to Delete] green flagged scenes in report." value="deleteSceneGreenFlag" id="green" style="background-color:#00FF00;color:black;" >Delete All Green Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-cancel" title="Delete all [Duplicate to Delete] orange flagged scenes in report." value="deleteSceneOrangeFlag" id="orange" style="background-color:orange;color:black;" >Delete All Orange Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-cancel" title="Delete all [Duplicate to Delete] yellow flagged scenes in report." value="deleteSceneYellowFlag" id="yellow" style="background-color:yellow;color:black;" >Delete All Yellow Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-cancel" title="Delete all [Duplicate to Delete] pink flagged scenes in report." value="deleteScenePinkFlag" id="pink" style="background-color:pink;color:black;" >Delete All Pink Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-cancel" title="Delete all [Duplicate to Delete] red flagged scenes in report." value="deleteSceneRedFlag" id="red" style="background-color:red;color:white;" >Delete All Red Flagged Scenes</button></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div iconCls="icon-copy" title="Copy the file from [Duplicate to Delete] to [Duplicate to Keep] for all [Duplicate to Delete] flagged scenes.">
|
||||||
|
<span>Copy Flagged Scenes</span>
|
||||||
|
<div>
|
||||||
|
<div iconCls="icon-copy-clear" title="Copy all cyan flagged scenes in report." value="copySceneCyanFlag" id="cyan" style="background-color:cyan;color:black;" >Copy All Cyan Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-copy-clear" title="Copy all green flagged scenes in report." value="copySceneGreenFlag" id="green" style="background-color:#00FF00;color:black;" >Copy All Green Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-copy-clear" title="Copy all orange flagged scenes in report." value="copySceneOrangeFlag" id="orange" style="background-color:orange;color:black;" >Copy All Orange Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-copy-clear" title="Copy all yellow flagged scenes in report." value="copySceneYellowFlag" id="yellow" style="background-color:yellow;color:black;" >Copy All Yellow Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-copy-clear" title="Copy all pink flagged scenes in report." value="copyScenePinkFlag" id="pink" style="background-color:pink;color:black;" >Copy All Pink Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-copy-clear" title="Copy all red flagged scenes in report." value="copySceneRedFlag" id="red" style="background-color:red;color:white;" >Copy All Red Flagged Scenes</button></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div iconCls="icon-documents" title="Copy the file and metadata (Tags, Performers, & Galleries) from [Duplicate to Delete] to [Duplicate to Keep] for all [Duplicate to Delete] flagged scenes.">
|
||||||
|
<span>Move Flagged Scenes</span>
|
||||||
|
<div>
|
||||||
|
<div iconCls="icon-documents" title="Move all cyan flagged scenes in report." value="moveSceneCyanFlag" id="cyan" style="background-color:cyan;color:black;" >Move All Cyan Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-documents" title="Move all green flagged scenes in report." value="moveSceneGreenFlag" id="green" style="background-color:#00FF00;color:black;" >Move All Green Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-documents" title="Move all orange flagged scenes in report." value="moveSceneOrangeFlag" id="orange" style="background-color:orange;color:black;" >Move All Orange Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-documents" title="Move all yellow flagged scenes in report." value="moveSceneYellowFlag" id="yellow" style="background-color:yellow;color:black;" >Move All Yellow Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-documents" title="Move all pink flagged scenes in report." value="moveScenePinkFlag" id="pink" style="background-color:pink;color:black;" >Move All Pink Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-documents" title="Move all red flagged scenes in report." value="moveSceneRedFlag" id="red" style="background-color:red;color:white;" >Move All Red Flagged Scenes</button></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div iconCls="icon-merge" title="Merge scene metadata from [Duplicate to Delete] to [Duplicate to Keep] for all [Duplicate to Delete] flagged scenes. This action make take a few minutes to complete.">
|
||||||
|
<span>Merge (Tags, Performers, & Galleries) Flagged Scenes</span>
|
||||||
|
<div>
|
||||||
|
<div iconCls="icon-merge" title="Merge all cyan flagged scenes in report." value="mergeSceneCyanFlag" id="cyan" style="background-color:cyan;color:black;" >Merge All Cyan Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-merge" title="Merge all green flagged scenes in report." value="mergeSceneGreenFlag" id="green" style="background-color:#00FF00;color:black;" >Merge All Green Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-merge" title="Merge all orange flagged scenes in report." value="mergeSceneOrangeFlag" id="orange" style="background-color:orange;color:black;" >Merge All Orange Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-merge" title="Merge all yellow flagged scenes in report." value="mergeSceneYellowFlag" id="yellow" style="background-color:yellow;color:black;" >Merge All Yellow Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-merge" title="Merge all pink flagged scenes in report." value="mergeScenePinkFlag" id="pink" style="background-color:pink;color:black;" >Merge All Pink Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-merge" title="Merge all red flagged scenes in report." value="mergeSceneRedFlag" id="red" style="background-color:red;color:white;" >Merge All Red Flagged Scenes</button></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div iconCls="icon-lock" title="Add special tag [_ExcludeDuplicateMarkForDeletion] for [Duplicate to Delete] scenes flagged with selected flag.">
|
||||||
|
<span>Add Exclude TAG to Flagged Scenes</span>
|
||||||
|
<div>
|
||||||
|
<div iconCls="icon-lock" title="Add Exclude TAG to all [Duplicate to Delete] cyan flagged scenes in report." value="addExcludeTagCyanFlag" id="cyan" style="background-color:cyan;color:black;" >Add Exclude TAG to Cyan Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-lock" title="Add Exclude TAG to all [Duplicate to Delete] green flagged scenes in report." value="addExcludeTagGreenFlag" id="green" style="background-color:#00FF00;color:black;" >Add Exclude TAG to Green Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-lock" title="Add Exclude TAG to all [Duplicate to Delete] orange flagged scenes in report." value="addExcludeTagOrangeFlag" id="orange" style="background-color:orange;color:black;" >Add Exclude TAG to Orange Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-lock" title="Add Exclude TAG to all [Duplicate to Delete] yellow flagged scenes in report." value="addExcludeTagYellowFlag" id="yellow" style="background-color:yellow;color:black;" >Add Exclude TAG to Yellow Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-lock" title="Add Exclude TAG to all [Duplicate to Delete] pink flagged scenes in report." value="addExcludeTagPinkFlag" id="pink" style="background-color:pink;color:black;" >Add Exclude TAG to Pink Flagged Scenes</button></div>
|
||||||
|
<div iconCls="icon-lock" title="Add Exclude TAG to all [Duplicate to Delete] red flagged scenes in report." value="addExcludeTagRedFlag" id="red" style="background-color:red;color:white;" >Add Exclude TAG to Red Flagged Scenes</button></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-sep"></div>
|
||||||
|
<div iconCls="icon-eraser-minus" id="clearAllSceneFlags" value="clearAllSceneFlags" title="Remove all flags from report for all scenes, except for deletion flag.">Clear All Flags from All Scenes</button></div>
|
||||||
|
<div iconCls="icon-eraser-minus" class="easyui-tooltip" title="Clear specific flag from all scenes.">
|
||||||
|
<span>Clear Flag from All Scenes</span>
|
||||||
|
<div>
|
||||||
|
<div iconCls="icon-eraser-minus" title="Clear flag cyan from all scenes." value="clearFlagCyanFlag" id="cyan" style="background-color:cyan;color:black;" >Clear Cyan</button></div>
|
||||||
|
<div iconCls="icon-eraser-minus" title="Clear flag green from all scenes." value="clearFlagGreenFlag" id="green" style="background-color:#00FF00;color:black;" >Clear Green</button></div>
|
||||||
|
<div iconCls="icon-eraser-minus" title="Clear flag orange from all scenes." value="clearFlagOrangeFlag" id="orange" style="background-color:orange;color:black;" >Clear Orange</button></div>
|
||||||
|
<div iconCls="icon-eraser-minus" title="Clear flag yellow from all scenes." value="clearFlagYellowFlag" id="yellow" style="background-color:yellow;color:black;" >Clear Yellow</button></div>
|
||||||
|
<div iconCls="icon-eraser-minus" title="Clear flag pink from all scenes." value="clearFlagPinkFlag" id="pink" style="background-color:pink;color:black;" >Clear Pink</button></div>
|
||||||
|
<div iconCls="icon-eraser-minus" title="Clear flag red from all scenes." value="clearFlagRedFlag" id="red" style="background-color:red;color:white;" >Clear Red</button></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td><input type="checkbox" id="RemoveValidatePrompt" name="RemoveValidatePrompt"><label for="RemoveValidatePrompt" title="Disable notice for task completion (Popup).">Disable Complete Confirmation</label><br></td>
|
||||||
|
<td><input type="checkbox" id="RemoveToKeepConfirm" name="RemoveToKeepConfirm"><label for="RemoveToKeepConfirm" title="Disable confirmation prompts for delete scenes">Disable Delete Confirmation</label><br></td>
|
||||||
|
|
||||||
|
</tr></table></td>
|
||||||
|
</tr></table></center>
|
||||||
|
<h2>Stash Duplicate Scenes Report (MatchTypePlaceHolder)</h2>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# DupFileManager: Ver 1.1.1 (By David Maisonave)
|
# DupFileManager: Ver 1.1.2 (By David Maisonave)
|
||||||
|
|
||||||
DupFileManager is a [Stash](https://github.com/stashapp/stash) plugin which manages duplicate files in the Stash system.
|
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.
|
It has both **task** and **tools-UI** components.
|
||||||
|
|||||||
@@ -18,57 +18,72 @@ html.wait, html.wait * { cursor: wait !important; }
|
|||||||
<script src="https://www.axter.com/js/jquery.prompt.js"></script>
|
<script src="https://www.axter.com/js/jquery.prompt.js"></script>
|
||||||
<link rel="stylesheet" href="https://www.axter.com/js/jquery.prompt.css"/>
|
<link rel="stylesheet" href="https://www.axter.com/js/jquery.prompt.css"/>
|
||||||
<script>
|
<script>
|
||||||
var apiKey = ""; // For Stash installations with a password setup, populate this variable with the apiKey found in Stash->Settings->Security->[API Key]; ----- Or pass in the apiKey at the URL command line. Example: advance_options.html?apiKey=12345G4igiJdgssdgiwqInh5cCI6IkprewJ9hgdsfhgfdhd&GQL=http://localhost:9999/graphql
|
const isChrome = !!window.chrome;
|
||||||
var GraphQl_URL = "http://localhost:9999/graphql";// For Stash installations with non-standard ports or URL's, populate this variable with actual URL; ----- Or pass in the URL at the command line using GQL param. Example: advance_options.html?GQL=http://localhost:9900/graphql
|
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
if (urlParams.get('apiKey') != null && urlParams.get('apiKey') !== "")
|
let thisUrl = "" + window.location;
|
||||||
apiKey = urlParams.get('apiKey');
|
const isAxterCom = (thisUrl.search("axter.com") > -1);
|
||||||
if (urlParams.get('GQL') != null && urlParams.get('GQL') !== "")
|
function getParam(ParamName, DefaultValue = ""){
|
||||||
GraphQl_URL = urlParams.get('GQL');
|
if (urlParams.get(ParamName) != null && urlParams.get(ParamName) !== "")
|
||||||
|
return urlParams.get(ParamName);
|
||||||
|
return DefaultValue;
|
||||||
|
}
|
||||||
|
const apiKey = getParam("apiKey"); // For Stash installations with a password setup, populate this variable with the apiKey found in Stash->Settings->Security->[API Key]; ----- Or pass in the apiKey at the URL command line. Example: advance_options.html?apiKey=12345G4igiJdgssdgiwqInh5cCI6IkprewJ9hgdsfhgfdhd&GQL=http://localhost:9999/graphql
|
||||||
|
const GraphQl_URL = getParam("GQL", "http://localhost:9999/graphql");// For Stash installations with non-standard ports or URL's, populate this variable with actual URL; ----- Or pass in the URL at the command line using GQL param. Example: advance_options.html?GQL=http://localhost:9900/graphql
|
||||||
|
var ReportUrlDir = getParam("ReportUrlDir")
|
||||||
|
const IS_DOCKER = getParam("IS_DOCKER") === "True";
|
||||||
|
var ReportUrl = "";
|
||||||
|
// let stash_site = { GQL: GraphQl_URL, apiKey: apiKey, ReportUrlDir: ReportUrlDir, };
|
||||||
|
// document.cookie = 'stash_site=' + JSON.stringify(stash_site);
|
||||||
console.log(urlParams);
|
console.log(urlParams);
|
||||||
console.log("GQL = " + GraphQl_URL);
|
console.log("GQL = " + GraphQl_URL + "; apiKey = " + apiKey + "; ReportUrlDir = " + ReportUrlDir + "; isChrome = " + isChrome + "; isAxterCom = " + isAxterCom + "; IS_DOCKER = " + IS_DOCKER + "; Cookies = " + document.cookie);
|
||||||
console.log("Key = " + apiKey);
|
|
||||||
|
|
||||||
function RunPluginDupFileManager(Mode, Param = 0, Async = false, TagOnlyScenes = false) {
|
// DockerWarning = "<p><b>Warning: </b>The current version of DupFileManager does not support accessing report files from Docker Stash setup.</p><p>The link in the bottom of this window will not work unless you're using a browser in the Docker OS.</p>Consider installing Firefox by using instructions in following link:<a href=\"https://collabnix.com/running-firefox-in-docker-container/\" target=\"_blank\" id=\"advance_options\">Firefox-in-Docker-Container</a><p>...</p>";
|
||||||
|
DockerWarning = "<p><b>Warning: </b>The current version of DupFileManager does not support accessing report files from Docker Stash setup.</p><p>The following link will not work unless you're using a browser in the Docker OS.</p>";
|
||||||
|
|
||||||
|
function RunPluginDupFileManager(Mode, Param = 0, Async = false, TagOnlyScenes = false, DataType = "text") {
|
||||||
// alert("Mode = " + Mode + ";Param = " + Param);
|
// alert("Mode = " + Mode + ";Param = " + Param);
|
||||||
$('html').addClass('wait');
|
$('html').addClass('wait');
|
||||||
$("body").css("cursor", "progress");
|
$("body").css("cursor", "progress");
|
||||||
if (TagOnlyScenes)
|
if (TagOnlyScenes)
|
||||||
Param += ":TagOnlyScenes";
|
Param += ":TagOnlyScenes";
|
||||||
console.log("GraphQl_URL = " + GraphQl_URL + "; Mode = " + Mode + "; Param = " + Param);
|
console.log("GraphQl_URL = " + GraphQl_URL + "; Mode = " + Mode + "; Param = " + Param + "; DataType = " + DataType);
|
||||||
if (apiKey !== ""){
|
if (apiKey !== ""){
|
||||||
console.log("Using apiKey = " + apiKey);
|
console.log("Using apiKey = " + apiKey);
|
||||||
$.ajaxSetup({beforeSend: function(xhr) {xhr.setRequestHeader('apiKey', apiKey);}});
|
$.ajaxSetup({beforeSend: function(xhr) {xhr.setRequestHeader('apiKey', apiKey);}});
|
||||||
}
|
}
|
||||||
$.ajax({method: "POST", url: GraphQl_URL, contentType: "application/json", dataType: "text", cache: Async, async: Async,
|
const AjaxData = $.ajax({method: "POST", url: GraphQl_URL, contentType: "application/json", dataType: DataType, 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" : Param, "mode":Mode}},
|
variables: {"plugin_id": "DupFileManager", "args": { "Target" : Param, "mode":Mode}},
|
||||||
}), success: function(result){
|
}), success: function(result){
|
||||||
$('html').removeClass('wait');
|
$('html').removeClass('wait');
|
||||||
$("body").css("cursor", "default");
|
$("body").css("cursor", "default");
|
||||||
if (result.startsWith("{\"errors\"")){
|
if (DataType === "text"){
|
||||||
console.log("Ajax FAILED with result = " + result);
|
if (result.startsWith("{\"errors\"")){
|
||||||
if (result.indexOf("{\"runPluginOperation\":null}") > 0)
|
console.log("Ajax FAILED with result = " + result);
|
||||||
alert("Stash RunPluginOperation failed with possible source code error.\nCheck Stash logging for details.\n\nResults = " + result);
|
if (result.indexOf("{\"runPluginOperation\":null}") > 0)
|
||||||
else
|
alert("Stash RunPluginOperation failed with possible source code error.\nCheck Stash logging for details.\n\nResults = " + result);
|
||||||
alert("Stash RunPluginOperation failed with result = " + result);
|
else
|
||||||
return;
|
alert("Stash RunPluginOperation failed with result = " + result);
|
||||||
}
|
return;
|
||||||
console.log("Ajax success with result = " + result);
|
}
|
||||||
if (Mode === "tag_duplicates_task" || Mode === "create_duplicate_report_task"){
|
console.log("Ajax success with result = " + result);
|
||||||
if (result.indexOf("\"Report complete\"") == -1)
|
if (Mode === "tag_duplicates_task" || Mode === "create_duplicate_report_task"){
|
||||||
alert("Stash RunPluginOperation returned unexpected results.\nNot sure if report completed successfully.\n\nResults = " + result);
|
if (result.indexOf("\"Report complete\"") == -1)
|
||||||
else
|
alert("Stash RunPluginOperation returned unexpected results.\nNot sure if report completed successfully.\n\nResults = " + result);
|
||||||
$('<p>Report complete. Click on OK to open report in browser.</p>').confirm(function(retrn){
|
else{
|
||||||
if(retrn.response){
|
var Notice = "";
|
||||||
var reportUrl = window.location.href;
|
var Instructions = "<p>Click the below link to open report in your browser.</p>";
|
||||||
reportUrl = reportUrl.replace("advance_options.html", "report/DuplicateTagScenes.html");
|
if (IS_DOCKER)
|
||||||
console.log("reportUrl = " + reportUrl);
|
Instructions = DockerWarning;
|
||||||
window.open(reportUrl, "_blank");
|
if (isAxterCom && isChrome)
|
||||||
}
|
Notice = "<p>Note: If your browser does not support opening local file links from a non-local URL, copy and paste the above link to your browser address field.</p>";
|
||||||
});
|
$("<h2>Report complete!</h2>" + Instructions + "<a href=\"" + ReportUrl + "\" target=\"_blank\" id=\"advance_options\">" + ReportUrl + "</a>" + Notice).alert();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
console.log("Ajax JSON results = " + JSON.stringify(result));
|
||||||
}, error: function(XMLHttpRequest, textStatus, errorThrown) {
|
}, error: function(XMLHttpRequest, textStatus, errorThrown) {
|
||||||
console.log("Ajax failed with Status: " + textStatus + "; Error: " + errorThrown);
|
console.log("Ajax failed with Status: " + textStatus + "; Error: " + errorThrown);
|
||||||
$('html').removeClass('wait');
|
$('html').removeClass('wait');
|
||||||
@@ -76,7 +91,27 @@ function RunPluginDupFileManager(Mode, Param = 0, Async = false, TagOnlyScenes =
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log("Setting default cursor");
|
console.log("Setting default cursor");
|
||||||
|
if (DataType == "text"){
|
||||||
|
console.log(AjaxData.responseText);
|
||||||
|
return AjaxData.responseText;
|
||||||
|
}
|
||||||
|
JsonStr = AjaxData.responseJSON.data.runPluginOperation.replaceAll("'", "\"");
|
||||||
|
console.log("JSON runPluginOperation = " + JsonStr);
|
||||||
|
return JSON.parse(JsonStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function GetReportUrlDir(){
|
||||||
|
var LocalDuplicateReport = RunPluginDupFileManager("getLocalDupReportPath", 0, false, false, "json");
|
||||||
|
console.log("LocalDuplicateReport.LocalDupReportExist = " + LocalDuplicateReport.LocalDupReportExist);
|
||||||
|
console.log("LocalDuplicateReport.Path = " + LocalDuplicateReport.Path);
|
||||||
|
ReportUrl = LocalDuplicateReport.ReportUrl;
|
||||||
|
console.log("ReportUrl = " + ReportUrl);
|
||||||
|
return LocalDuplicateReport.ReportUrlDir;
|
||||||
|
}
|
||||||
|
if (ReportUrlDir === "")
|
||||||
|
ReportUrlDir = GetReportUrlDir();
|
||||||
|
console.log("ReportUrlDir = " + ReportUrlDir);
|
||||||
|
|
||||||
function GetStashTabUrl(Tab){
|
function GetStashTabUrl(Tab){
|
||||||
var Url = GraphQl_URL;
|
var Url = GraphQl_URL;
|
||||||
Url = Url.replace("graphql", "settings?tab=" + Tab);
|
Url = Url.replace("graphql", "settings?tab=" + Tab);
|
||||||
@@ -122,10 +157,16 @@ function ProcessClick(This_){
|
|||||||
}
|
}
|
||||||
else if (ID === "viewreport")
|
else if (ID === "viewreport")
|
||||||
{
|
{
|
||||||
var reportUrl = window.location.href;
|
if (IS_DOCKER)
|
||||||
reportUrl = reportUrl.replace("advance_options.html", "report/DuplicateTagScenes.html");
|
$(DockerWarning + "<a href=\"" + ReportUrl + "\" target=\"_blank\" id=\"advance_options\">" + ReportUrl + "</a>").alert();
|
||||||
console.log("reportUrl = " + reportUrl);
|
else if (isAxterCom){
|
||||||
window.open(reportUrl, "_blank");
|
if (isChrome)
|
||||||
|
$("<p>This browser does not support local file links from a non-local URL. To open the report, copy and paste the following link to your browser address bar.</p><a href=\"" + ReportUrl + "\" target=\"_blank\" id=\"advance_options\">" + ReportUrl + "</a>").alert();
|
||||||
|
else
|
||||||
|
$("<p>If this browser supports local file links from a non-local URL, you can click on the following link to open your report. Other wise to open the report, copy and paste the link to your browser address bar.</p><a href=\"" + ReportUrl + "\" target=\"_blank\" id=\"advance_options\">" + ReportUrl + "</a>").alert();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
window.open(ReportUrl, "_blank");
|
||||||
}
|
}
|
||||||
else if (ID === "viewStashPlugin")
|
else if (ID === "viewStashPlugin")
|
||||||
window.open(GetStashTabUrl("plugins"), "_blank");
|
window.open(GetStashTabUrl("plugins"), "_blank");
|
||||||
@@ -298,12 +339,10 @@ function DeleteDupInPath(){
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<center>
|
<div class="easyui-accordion" data-options="multiple:true" style="width:800px;margin: auto;">
|
||||||
<div class="easyui-accordion" data-options="multiple:true" style="width:800px;">
|
|
||||||
<div title="Menu" data-options="iconCls:'icon-ok'" style="overflow:auto;padding:10px;">
|
<div title="Menu" data-options="iconCls:'icon-ok'" style="overflow:auto;padding:10px;">
|
||||||
<center>
|
<table style="color:darkgreen;background-color:powderblue;margin: auto;">
|
||||||
<table style="color:darkgreen;background-color:powderblue;">
|
<tr style="text-align:center;"><th><div><b style="color:red;"><i>DupFileManager</i></b></div>Advance Duplicate File Menu</th><th>Apply Multiple Options</th></tr>
|
||||||
<tr><th><div><b style="color:red;"><i>DupFileManager</i></b></div>Advance Duplicate File Menu</th><th>Apply Multiple Options</th></tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<table style="border-collapse: collapse; border: none;">
|
<table style="border-collapse: collapse; border: none;">
|
||||||
@@ -1956,9 +1995,8 @@ function DeleteDupInPath(){
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div title="Create Report Options" data-options="iconCls:'icon-menu2'" style="overflow:auto;padding:10px;">
|
<div title="Create Report Options" data-options="iconCls:'icon-menu2'" style="overflow:auto;padding:10px;">
|
||||||
<center>
|
<table style="color:darkgreen;background-color:powderblue;margin: auto;">
|
||||||
<table style="color:darkgreen;background-color:powderblue;">
|
<tr style="text-align:center;"><th colspan="3">
|
||||||
<tr><th colspan="3">
|
|
||||||
These options override the UI plugin user settings and the DupFileManager_config.py settings.
|
These options override the UI plugin user settings and the DupFileManager_config.py settings.
|
||||||
<div style="font-size: 10px;">These options apply to <b>[Create Duplicate Report]</b> <b style="color:red;background-color:yellow">sub-menu</b> options, that have specific <b style="color:red;background-color:yellow">match</b> value.</div>
|
<div style="font-size: 10px;">These options apply to <b>[Create Duplicate Report]</b> <b style="color:red;background-color:yellow">sub-menu</b> options, that have specific <b style="color:red;background-color:yellow">match</b> value.</div>
|
||||||
</th></tr>
|
</th></tr>
|
||||||
@@ -2026,10 +2064,9 @@ function DeleteDupInPath(){
|
|||||||
<td><div class="easyui-tooltip" title="The size of preview video height. Default value is 120."><label for="VideoPreviewHeight">Preview Video Height:</label><input type="number" min="50" max="600" step="10" id="VideoPreviewHeight" name="VideoPreviewHeight" value="120"></div></td>
|
<td><div class="easyui-tooltip" title="The size of preview video height. Default value is 120."><label for="VideoPreviewHeight">Preview Video Height:</label><input type="number" min="50" max="600" step="10" id="VideoPreviewHeight" name="VideoPreviewHeight" value="120"></div></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</center>
|
|
||||||
</div>
|
</div>
|
||||||
<div title="Help" data-options="iconCls:'icon-help', selected:'false'" style="padding:10px;">
|
<div title="Help" data-options="iconCls:'icon-help', selected:'false'" style="padding:10px;">
|
||||||
<table style="color:darkgreen;background-color:powderblue;">
|
<table style="color:darkgreen;background-color:powderblue;margin: auto;">
|
||||||
<tr><td style="font-size: 12px;" colspan="2">
|
<tr><td style="font-size: 12px;" colspan="2">
|
||||||
<ol type="I" style="padding-left: 16px;">
|
<ol type="I" style="padding-left: 16px;">
|
||||||
<li>Match Duplicate Distance Number Details</li>
|
<li>Match Duplicate Distance Number Details</li>
|
||||||
@@ -2113,7 +2150,7 @@ function DeleteDupInPath(){
|
|||||||
</ol>
|
</ol>
|
||||||
</ol>
|
</ol>
|
||||||
</ol>
|
</ol>
|
||||||
<li>List</b></li>
|
<li><b>List</b></li>
|
||||||
<ol type="1" style="padding-left: 16px;">
|
<ol type="1" style="padding-left: 16px;">
|
||||||
<li>DupFileManager supports 4 types of list that are configured in Stash=>Settings->Plugins->DupFileManager.</li>
|
<li>DupFileManager supports 4 types of list that are configured in Stash=>Settings->Plugins->DupFileManager.</li>
|
||||||
<ol type="A" style="padding-left: 16px;">
|
<ol type="A" style="padding-left: 16px;">
|
||||||
@@ -2155,9 +2192,8 @@ function DeleteDupInPath(){
|
|||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</center>
|
</div>
|
||||||
<div id="div1"></div>
|
<div id="div1"></div>
|
||||||
</center>
|
|
||||||
</body></html>
|
</body></html>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>menu demo</title>
|
|
||||||
<link rel="stylesheet" href="https://code.jquery.com/ui/1.13.3/themes/smoothness/jquery-ui.css">
|
|
||||||
<style>
|
|
||||||
.ui-menu {
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script src="https://code.jquery.com/jquery-3.7.1.js"></script>
|
|
||||||
<script src="https://code.jquery.com/ui/1.13.3/jquery-ui.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<ul id="menu">
|
|
||||||
<li>
|
|
||||||
<div>Item 1</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div>Item 2</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div>Item 3</div>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<div>Item 3-1</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div>Item 3-2</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div>Item 3-3</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div>Item 4</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div>Item 5</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
$( "#menu" ).menu();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -89,4 +89,16 @@
|
|||||||
- A note is displayed and highlighted explaining to the user that they have to copy and pasted the link to the browser's address field.
|
- A note is displayed and highlighted explaining to the user that they have to copy and pasted the link to the browser's address field.
|
||||||
- On browsers like FireFox, a button is displayed instead, and no note is displayed.
|
- On browsers like FireFox, a button is displayed instead, and no note is displayed.
|
||||||
- Removed *.css and *.map files, which were not being used.
|
- Removed *.css and *.map files, which were not being used.
|
||||||
|
### 1.1.2
|
||||||
|
- Moved link to [**Advance Duplicate File Menu**] to https://stash.axter.com/1.1.2/advance_options.html
|
||||||
|
- This allows the Advance Menu to be accessed by Chrome, Edge and other Chrome based browsers which don't allow accessing local links from a non-local URL.
|
||||||
|
- Added additional warnings when detecting Chrome based browsers and when moving from non-local link to local link.
|
||||||
|
- Moved htmlReportPrefix field from the DupFileManager_report_config.py to DupFileManager_report_header.
|
||||||
|
- This was needed because Python on Docker gives an error when using tripple quoted strings.
|
||||||
|
- Made advance_options.html HTML5 compliance.
|
||||||
|
- Added additional details returned by getLocalDupReportPath to include (IS_DOCKER, ReportUrl, AdvMenuUrl, apikey, & LocalDir).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user