First non-beta release for FileMonitor Plugin

- Added Tools-UI option to get FileMonitor running status.
- Added Stash toolbar icon to get FileMonitor running status.
This commit is contained in:
David Maisonave
2024-11-29 07:11:04 -05:00
parent d19dd5cdc0
commit 655cf7051a
11 changed files with 214 additions and 72 deletions

View File

@@ -48,7 +48,6 @@
const React = PluginApi.React;
const GQL = PluginApi.GQL;
const { Button } = PluginApi.libraries.Bootstrap;
const { faEthernet } = PluginApi.libraries.FontAwesomeSolid;
const { Link, NavLink, } = PluginApi.libraries.ReactRouterDOM;
// ToolTip text
const CreateReportButtonToolTip = "Tag duplicate files, and create a new duplicate file report listing all duplicate files and using existing DupFileManager plugin options selected.";
@@ -57,12 +56,12 @@
const ShowReportButtonToolTip = "Open link to the duplicate file (HTML) report created in local path.";
const ReportMenuButtonToolTip = "Main report menu for DupFileManager. Create and show duplicate files on an HTML report.";
// Buttons
const DupFileManagerReportMenuButton = React.createElement(Link, { to: "/plugin/DupFileManager", title: ReportMenuButtonToolTip }, React.createElement(Button, null, "DupFileManager Report Menu"));
const ToolsMenuOptionButton = React.createElement(Link, { to: "/plugin/DupFileManager_ToolsAndUtilities", title: ToolsMenuToolTip }, React.createElement(Button, null, "DupFileManager Tools and Utilities"));
const DupFileManagerReportMenuButton = React.createElement(Link, { to: "/DupFileManager", title: ReportMenuButtonToolTip }, React.createElement(Button, null, "DupFileManager Report Menu"));
const ToolsMenuOptionButton = React.createElement(Link, { to: "/DupFileManager_ToolsAndUtilities", title: ToolsMenuToolTip }, React.createElement(Button, null, "DupFileManager Tools and Utilities"));
function GetShowReportButton(LocalDuplicateReportPath, ButtonText){return React.createElement("a", { href: LocalDuplicateReportPath, title: ShowReportButtonToolTip}, React.createElement(Button, null, ButtonText));}
function GetAdvanceMenuButton(){return React.createElement("a", { href: AdvanceMenuOptionUrl, title: "Open link to the [Advance Duplicate File Deletion Menu]."}, React.createElement(Button, null, "Show [Advance Duplicate File Deletion Menu]"));}
function GetCreateReportNoTagButton(ButtonText){return React.createElement(Link, { to: "/plugin/DupFileManager_CreateReportWithNoTagging", title: CreateReportNoTagButtonToolTip }, React.createElement(Button, null, ButtonText));}
function GetCreateReportButton(ButtonText){return React.createElement(Link, { to: "/plugin/DupFileManager_CreateReport", title: CreateReportButtonToolTip }, 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));}
const { LoadingIndicator, } = PluginApi.components;
const HomePage = () => {
@@ -132,34 +131,34 @@
React.createElement("p", null),
GetShowReportButton(GetLocalDuplicateReportPath(), "Show Duplicate-File Report"),
React.createElement("p", null),
React.createElement(Link, { to: "/plugin/DupFileManager_deleteLocalDupReportHtmlFiles", title: "Delete local HTML duplicate file report." }, React.createElement(Button, null, "Delete Duplicate-File Report HTML Files")),
React.createElement(Link, { to: "/DupFileManager_deleteLocalDupReportHtmlFiles", title: "Delete local HTML duplicate file report." }, React.createElement(Button, null, "Delete Duplicate-File Report HTML Files")),
React.createElement("hr", {class:"dotted"}),
React.createElement("h3", {class:"submenu"}, "Tagged Duplicates Options"),
React.createElement("p", null),
GetAdvanceMenuButton(),
React.createElement("p", null),
React.createElement(Link, { to: "/plugin/DupFileManager_deleteTaggedDuplicatesTask", title: "Delete scenes previously given duplicate tag (_DuplicateMarkForDeletion)." }, React.createElement(Button, null, "Delete Tagged Duplicates")),
React.createElement(Link, { to: "/DupFileManager_deleteTaggedDuplicatesTask", title: "Delete scenes previously given duplicate tag (_DuplicateMarkForDeletion)." }, React.createElement(Button, null, "Delete Tagged Duplicates")),
React.createElement("p", null),
React.createElement(Link, { to: "/plugin/DupFileManager_deleteBlackListTaggedDuplicatesTask", title: "Delete scenes only in blacklist which where previously given duplicate tag (_DuplicateMarkForDeletion)." }, React.createElement(Button, null, "Delete Tagged Duplicates in Blacklist Only")),
React.createElement(Link, { to: "/DupFileManager_deleteBlackListTaggedDuplicatesTask", title: "Delete scenes only in blacklist which where previously given duplicate tag (_DuplicateMarkForDeletion)." }, React.createElement(Button, null, "Delete Tagged Duplicates in Blacklist Only")),
React.createElement("p", null),
React.createElement(Link, { to: "/plugin/DupFileManager_deleteTaggedDuplicatesLwrResOrLwrDuration", title: "Delete scenes previously given duplicate tag (_DuplicateMarkForDeletion) and lower resultion or duration compare to primary (ToKeep) duplicate." }, React.createElement(Button, null, "Delete Low Res/Dur Tagged Duplicates")),
React.createElement(Link, { to: "/DupFileManager_deleteTaggedDuplicatesLwrResOrLwrDuration", title: "Delete scenes previously given duplicate tag (_DuplicateMarkForDeletion) and lower resultion or duration compare to primary (ToKeep) duplicate." }, React.createElement(Button, null, "Delete Low Res/Dur Tagged Duplicates")),
React.createElement("p", null),
React.createElement(Link, { to: "/plugin/DupFileManager_deleteBlackListTaggedDuplicatesLwrResOrLwrDuration", title: "Delete scenes only in blacklist which where previously given duplicate tag (_DuplicateMarkForDeletion) and lower resultion or duration compare to primary (ToKeep) duplicate." }, React.createElement(Button, null, "Delete Low Res/Dur Tagged Duplicates in Blacklist Only")),
React.createElement(Link, { to: "/DupFileManager_deleteBlackListTaggedDuplicatesLwrResOrLwrDuration", title: "Delete scenes only in blacklist which where previously given duplicate tag (_DuplicateMarkForDeletion) and lower resultion or duration compare to primary (ToKeep) duplicate." }, React.createElement(Button, null, "Delete Low Res/Dur Tagged Duplicates in Blacklist Only")),
React.createElement("p", null),
React.createElement("hr", {class:"dotted"}),
React.createElement("h3", {class:"submenu"}, "Tagged Management Options"),
React.createElement("p", null),
React.createElement(Link, { to: "/plugin/DupFileManager_ClearAllDuplicateTags", title: "Remove duplicate tag from all scenes. This task may take some time to complete." }, React.createElement(Button, null, "Clear All Duplicate Tags")),
React.createElement(Link, { to: "/DupFileManager_ClearAllDuplicateTags", title: "Remove duplicate tag from all scenes. This task may take some time to complete." }, React.createElement(Button, null, "Clear All Duplicate Tags")),
React.createElement("p", null),
React.createElement(Link, { to: "/plugin/DupFileManager_deleteAllDupFileManagerTags", title: "Delete all DupFileManager tags from stash." }, React.createElement(Button, null, "Delete All DupFileManager Tags")),
React.createElement(Link, { to: "/DupFileManager_deleteAllDupFileManagerTags", title: "Delete all DupFileManager tags from stash." }, React.createElement(Button, null, "Delete All DupFileManager Tags")),
React.createElement("p", null),
React.createElement(Link, { to: "/plugin/DupFileManager_tagGrayList", title: "Set tag _GraylistMarkForDeletion to scenes having DuplicateMarkForDeletion tag and that are in the Graylist." }, React.createElement(Button, null, "Tag Graylist")),
React.createElement(Link, { to: "/DupFileManager_tagGrayList", title: "Set tag _GraylistMarkForDeletion to scenes having DuplicateMarkForDeletion tag and that are in the Graylist." }, React.createElement(Button, null, "Tag Graylist")),
React.createElement("hr", {class:"dotted"}),
React.createElement("h3", {class:"submenu"}, "Miscellaneous Options"),
React.createElement(Link, { to: "/plugin/DupFileManager_generatePHASH_Matching", title: "Generate PHASH (Perceptual hashes) matching. Used for file comparisons." }, React.createElement(Button, null, "Generate PHASH (Perceptual hashes) Matching")),
React.createElement(Link, { to: "/DupFileManager_generatePHASH_Matching", title: "Generate PHASH (Perceptual hashes) matching. Used for file comparisons." }, React.createElement(Button, null, "Generate PHASH (Perceptual hashes) Matching")),
React.createElement("p", null),
React.createElement("p", null),
React.createElement("p", null),
@@ -276,40 +275,41 @@
}
return ToolsAndUtilities();
};
PluginApi.register.route("/plugin/DupFileManager", HomePage);
PluginApi.register.route("/plugin/DupFileManager_CreateReport", CreateReport);
PluginApi.register.route("/plugin/DupFileManager_CreateReportWithNoTagging", CreateReportWithNoTagging);
PluginApi.register.route("/plugin/DupFileManager_ToolsAndUtilities", ToolsAndUtilities);
PluginApi.register.route("/plugin/DupFileManager_ClearAllDuplicateTags", ClearAllDuplicateTags);
PluginApi.register.route("/plugin/DupFileManager_deleteLocalDupReportHtmlFiles", deleteLocalDupReportHtmlFiles);
PluginApi.register.route("/plugin/DupFileManager_deleteAllDupFileManagerTags", deleteAllDupFileManagerTags);
PluginApi.register.route("/plugin/DupFileManager_generatePHASH_Matching", generatePHASH_Matching);
PluginApi.register.route("/plugin/DupFileManager_tagGrayList", tagGrayList);
PluginApi.register.route("/plugin/DupFileManager_deleteTaggedDuplicatesTask", deleteTaggedDuplicatesTask);
PluginApi.register.route("/plugin/DupFileManager_deleteBlackListTaggedDuplicatesTask", deleteBlackListTaggedDuplicatesTask);
PluginApi.register.route("/plugin/DupFileManager_deleteTaggedDuplicatesLwrResOrLwrDuration", deleteTaggedDuplicatesLwrResOrLwrDuration);
PluginApi.register.route("/plugin/DupFileManager_deleteBlackListTaggedDuplicatesLwrResOrLwrDuration", deleteBlackListTaggedDuplicatesLwrResOrLwrDuration);
PluginApi.register.route("/DupFileManager", HomePage);
PluginApi.register.route("/DupFileManager_CreateReport", CreateReport);
PluginApi.register.route("/DupFileManager_CreateReportWithNoTagging", CreateReportWithNoTagging);
PluginApi.register.route("/DupFileManager_ToolsAndUtilities", ToolsAndUtilities);
PluginApi.register.route("/DupFileManager_ClearAllDuplicateTags", ClearAllDuplicateTags);
PluginApi.register.route("/DupFileManager_deleteLocalDupReportHtmlFiles", deleteLocalDupReportHtmlFiles);
PluginApi.register.route("/DupFileManager_deleteAllDupFileManagerTags", deleteAllDupFileManagerTags);
PluginApi.register.route("/DupFileManager_generatePHASH_Matching", generatePHASH_Matching);
PluginApi.register.route("/DupFileManager_tagGrayList", tagGrayList);
PluginApi.register.route("/DupFileManager_deleteTaggedDuplicatesTask", deleteTaggedDuplicatesTask);
PluginApi.register.route("/DupFileManager_deleteBlackListTaggedDuplicatesTask", deleteBlackListTaggedDuplicatesTask);
PluginApi.register.route("/DupFileManager_deleteTaggedDuplicatesLwrResOrLwrDuration", deleteTaggedDuplicatesLwrResOrLwrDuration);
PluginApi.register.route("/DupFileManager_deleteBlackListTaggedDuplicatesLwrResOrLwrDuration", deleteBlackListTaggedDuplicatesLwrResOrLwrDuration);
PluginApi.patch.before("SettingsToolsSection", function (props) {
const { Setting, } = PluginApi.components;
return [
{
children: (React.createElement(React.Fragment, null,
props.children,
React.createElement(Setting, { heading: React.createElement(Link, { to: "/plugin/DupFileManager", title: ReportMenuButtonToolTip }, React.createElement(Button, null, "Duplicate File Report (DupFileManager)"))}),
React.createElement(Setting, { heading: React.createElement(Link, { to: "/plugin/DupFileManager_ToolsAndUtilities", title: ToolsMenuToolTip }, React.createElement(Button, null, "DupFileManager Tools and Utilities"))}),
React.createElement(Setting, { heading: React.createElement(Link, { to: "/DupFileManager", title: ReportMenuButtonToolTip }, React.createElement(Button, null, "Duplicate File Report (DupFileManager)"))}),
React.createElement(Setting, { heading: React.createElement(Link, { to: "/DupFileManager_ToolsAndUtilities", title: ToolsMenuToolTip }, React.createElement(Button, null, "DupFileManager Tools and Utilities"))}),
)),
},
];
});
const { faFileVideo } = PluginApi.libraries.FontAwesomeSolid;
PluginApi.patch.before("MainNavBar.UtilityItems", function (props) {
const { Icon, } = PluginApi.components;
return [
{
children: (React.createElement(React.Fragment, null,
props.children,
React.createElement(NavLink, { className: "nav-utility", exact: true, to: "/plugin/DupFileManager" },
React.createElement(NavLink, { className: "nav-utility", exact: true, to: "/DupFileManager" },
React.createElement(Button, { className: "minimal d-flex align-items-center h-100", title: ReportMenuButtonToolTip },
React.createElement(Icon, { icon: faEthernet })))))
React.createElement(Icon, { icon: faFileVideo }))))) // faFileVideo fa-FileImport
}
];
});

View File

@@ -1,6 +1,6 @@
name: DupFileManager
description: Manages duplicate files.
version: 1.0.0
version: 1.0.1
url: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/DupFileManager
ui:
javascript:

View File

@@ -1,4 +1,4 @@
# DupFileManager: Ver 1.0.0 (By David Maisonave)
# DupFileManager: Ver 1.0.1 (By David Maisonave)
DupFileManager is a [Stash](https://github.com/stashapp/stash) plugin which manages duplicate files in the Stash system.
It has both **task** and **tools-UI** components.
@@ -101,9 +101,10 @@ That's it!!!
- Full bottom extended portion of the Advanced Menu screen.
- ![Screenshot 2024-11-22 232208](https://github.com/user-attachments/assets/bf1f3021-3a8c-4875-9737-60ee3d7fe675)
### Future Planned Features
### Future Planned Features or Fixes
- Add logic to merge performers and galaries seperatly from tag merging on report. Planned for 1.5.0 Version.
- Add code to report to make it when the report updates the screen (due to tag merging), it stays in the same row position. Planned for 1.5.0 Version.
- Fix errors on HTML page listed in https://validator.w3.org. Planned for 1.9.0 Version.
- Add logic to merge group metadata when selecting merge option on report. Planned for 2.0.0 Version.
- Add advanced menu directly to the Settings->Tools menu. Planned for 2.0.0 Version.
- Add report directly to the Settings->Tools menu. Planned for 2.0.0 Version.

View File

@@ -281,31 +281,33 @@ function DeleteDupInPath(){
<tr><th><div><b style="color:red;"><i>DupFileManager</i></b></div>Advance Duplicate File Deletion Menu</th><th>Apply Multiple Options</th></tr>
<tr>
<td>
<table style="border-collapse: collapse; border: none;"><tr style="border: none;">
<table style="border-collapse: collapse; border: none;">
<tr><th colspan="3" style="font-size: 12px;border: none;">Create report overriding user [Match Duplicate Distance] and [significantTimeDiff] settings</th></tr>
<td style="border: none;"><div class="dropdown">
<button type="button" id="create_duplicate_report_task" value="-1" title="Create new report WITHOUT tags using user settings for [Match Duplicate Distance].">Create Duplicate Report <i class="fa fa-caret-down"></i></button>
<div class="dropdown-content">
<div><button type="button" id="create_duplicate_report_task0a" value="0" title="Create report using [Match Duplicate Distance]=0 (Exact Match). NO tagging.">Create Duplicate Report [Exact Match]</button></div>
<div><button type="button" id="create_duplicate_report_task1a" value="1" title="Create report using [Match Duplicate Distance]=1 (High Match). NO tagging.">Create Duplicate Report [High Match]</button></div>
<div><button type="button" id="create_duplicate_report_task2a" value="2" title="Create report using [Match Duplicate Distance]=2 (Medium Match). NO tagging.">Create Duplicate Report [Medium Match]</button></div>
<div><button type="button" id="create_duplicate_report_task3a" value="3" title="Create report using [Match Duplicate Distance]=3 (Low Match). NO tagging.">Create Duplicate Report [Low Match]</button></div>
<div style="height:2px;width:220px;border-width:0;color:gray;background-color:gray;">_</div>
<div><button type="button" id="tag_duplicates_task" value="-1" title="Create new report which tags duplicates with tag name _DuplicateMarkForDeletion using user settings for [Match Duplicate Distance].">Create Duplicate Report with Tagging (With Default Match Setting)</button></div>
<div><button type="button" id="tag_duplicates_task0a" value="0" title="Create report which tags duplicates with tag name _DuplicateMarkForDeletion_0 and using [Match Duplicate Distance]=0 (Exact Match).">Create Duplicate Tagging Report [Exact Match]</button></div>
<div><button type="button" id="tag_duplicates_task1a" value="1" title="Create report which tags duplicates with tag name _DuplicateMarkForDeletion_1 and using [Match Duplicate Distance]=1 (High Match).">Create Duplicate Tagging Report [High Match]</button></div>
<div><button type="button" id="tag_duplicates_task2a" value="2" title="Create report which tags duplicates with tag name _DuplicateMarkForDeletion_2 and using [Match Duplicate Distance]=2 (Medium Match).">Create Duplicate Tagging Report [Medium Match]</button></div>
<div><button type="button" id="tag_duplicates_task3a" value="3" title="Create report which tags duplicates with tag name _DuplicateMarkForDeletion_3 and using [Match Duplicate Distance]=3 (Low Match).">Create Duplicate Tagging Report [Low Match]</button></div>
</div>
</div></td>
<td style="border: none;padding: 0 15px;">
<label for="significantTimeDiff" title="Significant time difference setting, where 1 equals 100% and (.9) equals 90%.">Time Difference%:</label>
<input type="number" min="0.25" max="1.00" step="0.01" id="significantTimeDiff" name="significantTimeDiff" title="Significant time difference setting, where 1 equals 100% and (.9) equals 90%." value="0.90">
</td>
<td style="border: none;padding: 0 15px;">
<button type="button" id="viewreport" title="View duplicate file report.">View Dup Report</button>
</td>
</tr></table>
<tr>
<td style="border: none;"><div class="dropdown">
<button type="button" id="create_duplicate_report_task" value="-1" title="Create new report WITHOUT tags using user settings for [Match Duplicate Distance].">Create Duplicate Report <i class="fa fa-caret-down"></i></button>
<div class="dropdown-content">
<div><button type="button" id="create_duplicate_report_task0a" value="0" title="Create report using [Match Duplicate Distance]=0 (Exact Match). NO tagging.">Create Duplicate Report [Exact Match]</button></div>
<div><button type="button" id="create_duplicate_report_task1a" value="1" title="Create report using [Match Duplicate Distance]=1 (High Match). NO tagging.">Create Duplicate Report [High Match]</button></div>
<div><button type="button" id="create_duplicate_report_task2a" value="2" title="Create report using [Match Duplicate Distance]=2 (Medium Match). NO tagging.">Create Duplicate Report [Medium Match]</button></div>
<div><button type="button" id="create_duplicate_report_task3a" value="3" title="Create report using [Match Duplicate Distance]=3 (Low Match). NO tagging.">Create Duplicate Report [Low Match]</button></div>
<div style="height:2px;width:220px;border-width:0;color:gray;background-color:gray;">_</div>
<div><button type="button" id="tag_duplicates_task" value="-1" title="Create new report which tags duplicates with tag name _DuplicateMarkForDeletion using user settings for [Match Duplicate Distance].">Create Duplicate Report with Tagging (With Default Match Setting)</button></div>
<div><button type="button" id="tag_duplicates_task0a" value="0" title="Create report which tags duplicates with tag name _DuplicateMarkForDeletion_0 and using [Match Duplicate Distance]=0 (Exact Match).">Create Duplicate Tagging Report [Exact Match]</button></div>
<div><button type="button" id="tag_duplicates_task1a" value="1" title="Create report which tags duplicates with tag name _DuplicateMarkForDeletion_1 and using [Match Duplicate Distance]=1 (High Match).">Create Duplicate Tagging Report [High Match]</button></div>
<div><button type="button" id="tag_duplicates_task2a" value="2" title="Create report which tags duplicates with tag name _DuplicateMarkForDeletion_2 and using [Match Duplicate Distance]=2 (Medium Match).">Create Duplicate Tagging Report [Medium Match]</button></div>
<div><button type="button" id="tag_duplicates_task3a" value="3" title="Create report which tags duplicates with tag name _DuplicateMarkForDeletion_3 and using [Match Duplicate Distance]=3 (Low Match).">Create Duplicate Tagging Report [Low Match]</button></div>
</div>
</div></td>
<td style="border: none;padding: 0 15px;">
<label for="significantTimeDiff" title="Significant time difference setting, where 1 equals 100% and (.9) equals 90%.">Time Difference%:</label>
<input type="number" min="0.25" max="1.00" step="0.01" id="significantTimeDiff" name="significantTimeDiff" title="Significant time difference setting, where 1 equals 100% and (.9) equals 90%." value="0.90">
</td>
<td style="border: none;padding: 0 15px;">
<button type="button" id="viewreport" title="View duplicate file report.">View Dup Report</button>
</td>
</tr>
</table>
</td>
<td>
<div class="dropdown">
@@ -340,7 +342,7 @@ function DeleteDupInPath(){
<tr>
<td><form id="pathToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="pathToDeleteText">Path:</label>
<input type="text" id="pathToDeleteText" name="pathToDeleteText" value="C:\Downloads">
<input type="text" id="pathToDeleteText" name="pathToDeleteText" placeholder="C:\Downloads" value="">
<button type="button" id="pathToDelete" title="Delete tagged duplicates having file path">Delete Dup in Path</button>
<button type="button" id="pathToDeleteBlacklist" title="Delete blacklist tagged duplicates having file path">Del Blacklist Dup in Path</button>
</form>
@@ -350,7 +352,7 @@ function DeleteDupInPath(){
<tr>
<td><form id="sizeToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="sizeToDelete" title="File size in bytes.">File Size (bytes):</label>
<input type="number" id="sizeToDelete" name="sizeToDelete" title="File size in bytes." value="123456">
<input type="number" min="0" step="1000000" id="sizeToDelete" name="sizeToDelete" title="File size in bytes." placeholder="123456" value="">
<label for="sizeToDeleteLess">All:</label>
<button type="button" id="sizeToDeleteLess" title="Delete tagged duplicates with file size less than"><</button>
<button type="button" id="sizeToDeleteGreater" title="Delete tagged duplicates with file size greater than">></button>
@@ -370,7 +372,7 @@ function DeleteDupInPath(){
<tr>
<td><form id="durationToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="durationToDelete" title="Scene duration (time) in seconds.">Duration (seconds):</label>
<input type="number" min="1" max="14400" id="durationToDelete" name="durationToDelete" title="Duration in seconds." value="60">
<input type="number" min="1" max="14400" id="durationToDelete" name="durationToDelete" title="Duration in seconds." placeholder="60" value="">
<label for="durationToDeleteLess">All:</label>
<button type="button" id="durationToDeleteLess" title="Delete tagged duplicates with duration less than"><</button>
<button type="button" id="durationToDeleteGreater" title="Delete tagged duplicates with duration greater than">></button>
@@ -429,7 +431,7 @@ function DeleteDupInPath(){
<tr>
<td><form id="tagToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="tagToDelete" title="Scene with tag.">Tag:</label>
<input type="text" id="tagToDeleteText" name="tagToDelete" title="tag name." value="redhead">
<input type="text" id="tagToDeleteText" name="tagToDelete" title="tag name." placeholder="redhead" value="">
<label for="tagToDelete">All:</label>
<button type="button" id="tagToDelete" title="Delete tagged duplicates with tag name">Contains</button>
<label for="tagToDeleteBlacklist">Blacklist:</label>
@@ -441,7 +443,7 @@ function DeleteDupInPath(){
<tr>
<td><form id="titleToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="titleToDelete" title="Scene having value in title.">Title:</label>
<input type="text" id="titleToDeleteText" name="titleToDelete" title="String to search for in title." value="mature">
<input type="text" id="titleToDeleteText" name="titleToDelete" title="String to search for in title." placeholder="mature" value="">
<label for="titleToDelete">All:</label>
<button type="button" id="titleToDelete" title="Delete tagged duplicates with title name including value">Contains</button>
<label for="titleToDeleteBlacklist">Blacklist:</label>
@@ -453,7 +455,7 @@ function DeleteDupInPath(){
<tr>
<td><form id="pathStrToDeleteForm" action="javascript:DeleteDupInPath();" target="_self">
<label for="pathStrToDelete" pathStr="Scene having value in path.">Path String:</label>
<input type="text" id="pathStrToDeleteText" name="pathStrToDelete" pathStr="String to search for in path." value="blond">
<input type="text" id="pathStrToDeleteText" name="pathStrToDelete" pathStr="String to search for in path." placeholder="blond" value="">
<label for="pathStrToDelete">All:</label>
<button type="button" id="pathStrToDelete" pathStr="Delete tagged duplicates with path having value">Contains</button>
<label for="pathStrToDeleteBlacklist">Blacklist:</label>

View File

@@ -43,3 +43,7 @@
- This change was needed because sometimes the browser refuse to open local URL's with params on the URL.
- Using cookies also allows check options status to stay the same after refresh.
- Added code to [**Advance Duplicate File Deletion Menu**] to delete based on flags.
### 1.0.1
- Change [**Advance Duplicate File Deletion Menu**] default input values to placeholder text.
- Change stash toolbar icon for DupFileManager to a file icon with a video camera.
- Removed **plugin/** from the URL for the Tools-UI menu.

View File

@@ -1,4 +1,4 @@
# FileMonitor: Ver 0.9.2 (By David Maisonave)
# FileMonitor: Ver 1.0.0 (By David Maisonave)
FileMonitor is a [Stash](https://github.com/stashapp/stash) plugin with the following two main features:
@@ -170,3 +170,5 @@ Please use the following link to report FileMonitor bugs:
Please use the following link to report FileMonitor Feature Request:[FileMonitor Feature Reques](https://github.com/David-Maisonave/Axter-Stash/issues/new?assignees=&labels=Enhancement&projects=&template=feature_request_plugin.yml&title=%F0%9F%92%A1%EF%B8%8F%5BEnhancement%5D%3A%5BFileMonitor%5D+Your_Short_title)
Please do **NOT** use the feature request to include any problems associated with errors. Instead use the bug report for error issues.
### Future Planned Features or Fixes

File diff suppressed because one or more lines are too long

View File

@@ -5,19 +5,20 @@
# Example: python filemonitor.py --url http://localhost:9999
try:
import ModulesValidate
ModulesValidate.modulesInstalled(["stashapp-tools", "watchdog", "schedule", "requests"])
ModulesValidate.modulesInstalled(["stashapp-tools", "watchdog", "schedule", "requests"], silent=True)
except Exception as e:
import traceback, sys
tb = traceback.format_exc()
print(f"ModulesValidate Exception. Error: {e}\nTraceBack={tb}", file=sys.stderr)
from StashPluginHelper import StashPluginHelper
import os, sys, time, pathlib, argparse, platform, traceback, logging
from StashPluginHelper import StashPluginHelper
from StashPluginHelper import taskQueue
from threading import Lock, Condition
from multiprocessing import shared_memory
from filemonitor_config import config
from filemonitor_task_examples import task_examples
from filemonitor_self_unit_test import self_unit_test
from datetime import datetime
config['task_scheduler'] = config['task_scheduler'] + task_examples['task_scheduler']
if self_unit_test['selfUnitTest_repeat']:
@@ -62,6 +63,13 @@ stash = StashPluginHelper(
maxbytes=5*1024*1024,
apiKey=parse_args.apikey
)
doJsonReturnModeTypes = ["getFileMonitorRunningStatus"]
doJsonReturn = False
if len(sys.argv) < 2 and stash.PLUGIN_TASK_NAME in doJsonReturnModeTypes:
doJsonReturn = True
stash.log_to_norm = stash.LogTo.FILE
stash.status(logLevel=logging.DEBUG)
stash.Log(f"\nStarting (__file__={__file__}) (stash.CALLED_AS_STASH_PLUGIN={stash.CALLED_AS_STASH_PLUGIN}) (stash.DEBUG_TRACING={stash.DEBUG_TRACING}) (stash.DRY_RUN={stash.DRY_RUN}) (stash.PLUGIN_TASK_NAME={stash.PLUGIN_TASK_NAME})************************************************")
stash.Trace(f"stash.JSON_INPUT={stash.JSON_INPUT}")
@@ -72,6 +80,7 @@ signal = Condition(mutex)
shouldUpdate = False
SHAREDMEMORY_NAME = "DavidMaisonaveAxter_FileMonitor" # Unique name for shared memory
SHAREDMEMORY_SIZE = 4
RECURSIVE = stash.pluginSettings["recursiveDisabled"] == False
SCAN_MODIFIED = stash.pluginConfig["scanModified"]
RUN_CLEAN_AFTER_DELETE = stash.pluginConfig["runCleanAfterDelete"]
@@ -502,7 +511,7 @@ def start_library_monitor():
global lastScanJob
try:
# Create shared memory buffer which can be used as singleton logic or to get a signal to quit task from external script
shm_a = shared_memory.SharedMemory(name=SHAREDMEMORY_NAME, create=True, size=4)
shm_a = shared_memory.SharedMemory(name=SHAREDMEMORY_NAME, create=True, size=SHAREDMEMORY_SIZE)
except:
stash.Error(f"Could not open shared memory map ({SHAREDMEMORY_NAME}). Change File Monitor must be running. Can not run multiple instance of Change File Monitor. Stop FileMonitor before trying to start it again.")
return
@@ -743,7 +752,7 @@ def stop_library_monitor():
os.remove(SPECIAL_FILE_NAME)
stash.Trace("Opening shared memory map.")
try:
shm_a = shared_memory.SharedMemory(name=SHAREDMEMORY_NAME, create=False, size=4)
shm_a = shared_memory.SharedMemory(name=SHAREDMEMORY_NAME, create=False, size=SHAREDMEMORY_SIZE)
except:
# If FileMonitor is running as plugin, then it's expected behavior that SharedMemory will not be available.
stash.Trace(f"Could not open shared memory map ({SHAREDMEMORY_NAME}). Change File Monitor must not be running.")
@@ -759,7 +768,7 @@ def stop_library_monitor():
def start_library_monitor_service():
# First check if FileMonitor is already running
try:
shm_a = shared_memory.SharedMemory(name=SHAREDMEMORY_NAME, create=False, size=4)
shm_a = shared_memory.SharedMemory(name=SHAREDMEMORY_NAME, create=False, size=SHAREDMEMORY_SIZE)
shm_a.close()
shm_a.unlink()
stash.Error("FileMonitor is already running. Need to stop FileMonitor before trying to start it again.")
@@ -846,6 +855,21 @@ def manageTagggedScenes(clearTag=True):
runTypeID=0
runTypeName=["NothingToDo", "stop_library_monitor", "StartFileMonitorAsAServiceTaskID", "StartFileMonitorAsAPluginTaskID", "CommandLineStartLibMonitor"]
def getFileMonitorRunningStatus():
FileMonitorStatus = "NOT running"
try:
shm_a = shared_memory.SharedMemory(name=SHAREDMEMORY_NAME, create=False, size=SHAREDMEMORY_SIZE)
shm_a.close()
shm_a.unlink()
FileMonitorStatus = "RUNNING"
stash.Log("FileMonitor is running...")
except:
pass
stash.Log("FileMonitor is NOT running!!!")
stash.Log(f"{stash.PLUGIN_TASK_NAME} complete")
sys.stdout.write("{" + f"{stash.PLUGIN_TASK_NAME} : 'complete', FileMonitorStatus:'{FileMonitorStatus}'" + "}")
try:
if parse_args.stop or parse_args.restart or stash.PLUGIN_TASK_NAME == "stop_library_monitor":
runTypeID=1
@@ -876,6 +900,9 @@ try:
runTypeID=7
manageTagggedScenes()
stash.Trace(f"{CLEAR_SYNC_LIBRARY_TAG} EXIT")
elif stash.PLUGIN_TASK_NAME == "getFileMonitorRunningStatus":
getFileMonitorRunningStatus()
stash.Debug(f"{stash.PLUGIN_TASK_NAME} EXIT")
elif not stash.CALLED_AS_STASH_PLUGIN:
runTypeID=4
if parse_args.kill_job_task_que != None and parse_args.kill_job_task_que != "":
@@ -889,7 +916,8 @@ try:
except Exception as e:
tb = traceback.format_exc()
stash.Error(f"Exception while running FileMonitor. runType='{runTypeName[runTypeID]}'; Error: {e}\nTraceBack={tb}")
if doJsonReturn:
sys.stdout.write("{" + f"Exception : '{e}; See log file for TraceBack' " + "}")
stash.Trace("\n*********************************\nEXITING ***********************\n*********************************")
# ToDo: Add option to add path to library if path not included when calling metadata_scan

View File

@@ -1,7 +1,10 @@
name: FileMonitor
description: Monitors the Stash library folders, and updates Stash if any changes occurs in the Stash library paths.
version: 0.9.2
version: 1.0.0
url: https://github.com/David-Maisonave/Axter-Stash/tree/main/plugins/FileMonitor
ui:
javascript:
- filemonitor.js
settings:
recursiveDisabled:
displayName: No Recursive

View File

@@ -0,0 +1,4 @@
##### This page was added starting on version 1.0.0 to keep track of newly added features between versions.
### 1.0.0
- Added Tools-UI option to get FileMonitor running status.
- Added Stash toolbar icon to get FileMonitor running status.

View File

@@ -85,3 +85,5 @@ Please use the following link to report RenameFile Feature Request:[RenameFile F
Please do **NOT** use the feature request to include any problems associated with errors. Instead use the bug report for error issues.
**Note:** This script is **largely** based on the [Renamer](https://github.com/Serechops/Serechops-Stash/tree/main/plugins/Renamer) script.
### Future Planned Features or Fixes